SABnzbd-2.3.2/ABOUT.txt0000644000000000000000000000212213217005256012540 0ustar 00000000000000******************************************* *** This is SABnzbd 2.4.0 *** ******************************************* SABnzbd is an open-source cross-platform binary newsreader. It simplifies the process of downloading from Usenet dramatically, thanks to its friendly web-based user interface and advanced built-in post-processing options that automatically verify, repair, extract and clean up posts downloaded from Usenet. SABnzbd also has a fully customizable user interface, and offers a complete API for third-party applications to hook into. There is an extensive Wiki on the use of SABnzbd. https://sabnzbd.org/wiki/ Please also read the file "ISSUES.txt" The organization of the download queue is different from 0.7.x (and older). 1.0.0 will not finish downloading an existing queue. Also, your sabnzbd.ini file will be upgraded, making it incompatible with older releases. ******************************************* *** Upgrading from 0.7.x and below *** ******************************************* Empty your current queue Stop SABnzbd. Install new version Start SABnzbd. SABnzbd-2.3.2/COPYRIGHT.txt0000644000000000000000000000331613217005256013244 0ustar 00000000000000 (c) Copyright 2007-2017 by "The SABnzbd-team" The SABnzbd-team is: Active team: ShyPike inpheaux zoggy Safihre Sleeping members sw1tch pairofdimes rAf Honorary member (and original author) Gregor Kaufmann The main contributors and moderators of the translations Danish: Rene (nordjyden6), Scott Dutch: ShyPike, Safihre French : rAf, Fox Ace, Fred, Morback, Jih German: Severin Heiniger, Tim Hartmann, DonPizza, Alex Norwegian: Protx, mjelva, TomP, John Romanian: nicusor Serbian: Ozzii, Krišan Darko Swedish: Malmis, Kim Joahnsson, Patrik-liind, Chris M Spanish: Syquus, Adolfo Jayme Portuguese (Brazil): lrrosa, diegosps Russian: Pavel Maryanov Polish: Tomasz 'Zen' Napierala Chinese: XsLiDian Finnish: Matti Ylönen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. See accompanying files GPL2.txt and GPL3.txt. SABnzbd-2.3.2/GPL2.txt0000644000000000000000000004310613217005256012401 0ustar 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. SABnzbd-2.3.2/GPL3.txt0000644000000000000000000010451313217005256012402 0ustar 00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . SABnzbd-2.3.2/INSTALL.txt0000644000000000000000000001330513217005256013001 0ustar 00000000000000 SABnzbd 2.3.1 ------------------------------------------------------------------------------- 0) LICENSE ------------------------------------------------------------------------------- (c) Copyright 2007-2017 by "The SABnzbd-team" This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ------------------------------------------------------------------------------- 1) INSTALL with the Windows installer ------------------------------------------------------------------------------- Just run the downloaded EXE file and the installer will start. It's just a simple standard installer. After installation, find the SABnzbd program in the Start menu and start it. Within a few seconds your web browser will start and show the user interface. Use the "Help" button in the web-interface to be directed to the Help Wiki. ------------------------------------------------------------------------------- 2) INSTALL pre-built Windows binaries ------------------------------------------------------------------------------- Unzip pre-built version to any folder of your liking. Start the SABnzbd.exe program. Within a few seconds your web browser will start and show the user interface. Use the "Help" button in the web-interface to be directed to the Help Wiki. ------------------------------------------------------------------------------- 3) INSTALL pre-built macOS binaries ------------------------------------------------------------------------------- Download the DMG file, mount and drag the SABnzbd icon to Programs. Just like you do with so many apps. ------------------------------------------------------------------------------- 4) INSTALL with only sources ------------------------------------------------------------------------------- Specific guides to install from source are available for Windows and macOS: https://sabnzbd.org/wiki/installation/install-macos https://sabnzbd.org/wiki/installation/install-from-source-windows You need to have Python installed plus some non-standard Python modules and a few tools. All platforms Python-2.7.latest http://www.python.org (2.7.9+ recommended) Windows PyWin32 use "pip install pypiwin32" subprocessww use "pip install subprocessww" Essential modules cheetah-2.0.1+ use "pip install cheetah" par2cmdline >= 0.4 https://github.com/Parchive/par2cmdline/releases See also: https://sabnzbd.org/wiki/installation/multicore-par2 unrar >= 5.00+ http://www.rarlab.com/rar_add.htm openssl >= 1.0.0 http://www.openssl.org/ Optional modules unzip >= 6.00 http://www.info-zip.org/ 7zip >= 9.20 http://www.7zip.org/ sabyenc == 3.3.1 use "pip install sabyenc" More information: https://sabnzbd.org/sabyenc cryptography >= 1.0 use "pip install cryptography" Enables certificate generation and detection of encrypted RAR-files Optional modules Linux pynotify Should be part of GTK for Python support on Debian/Ubuntu If not, you cannot use the NotifyOSD feature. python-dbus Enable option to Shutdown/Restart/Standby PC on queue finish. Embedded modules (preferably use the included version) CherryPy-8.1.2 with patches http://www.cherrypy.org Unpack the ZIP-file containing the SABnzbd sources to any folder of your liking. If you want multiple languages, you need to compile the translations. Start this from a shell terminal (or command prompt): python tools/make_mo.py Start this from a shell terminal (or command prompt): python -OO SABnzbd.py Within a few seconds your web browser will start and show the user interface. Use the "Help" button in the web-interface to be directed to the Help Wiki. ------------------------------------------------------------------------------- 5) TROUBLESHOOTING ------------------------------------------------------------------------------- Your browser may start up with just an error page. This means that SABnzbd cannot use the default port 8080 to run its web-server on. Try to use another port, you'll need to use the a command window: SABnzbd.exe -s localhost:7777 or python SABnzbd.py -s localhost:7777 You may of course try other port numbers too. For troubleshooting on Windows you can use the program SABnzbd-console.exe. This will show a black window where logging information will be shown. This may help you solve problems easier. ------------------------------------------------------------------------------- 6) MORE INFORMATION ------------------------------------------------------------------------------- Visit our wiki: https://sabnzbd.org/wiki/ ------------------------------------------------------------------------------- 7) CREDITS ------------------------------------------------------------------------------- Several parts of SABnzbd were built by other people, illustrating the wonderful world of Free Open Source Software. See the licenses folder of the main program and of the skin folders. SABnzbd-2.3.2/ISSUES.txt0000644000000000000000000000716513217005256012715 0ustar 00000000000000******************************************* *** Known issues *** ******************************************* - To prevent unexpectedly large NZBs from eating your download quota you can set the option 'size_limit' on the Config->Special page. Any NZB larger than this size will be set to paused and get a low priority. - When par2 or unrar hang up, never just stop SABnzbd. Instead use your operating system's task manager to stop the par2 or unrar program. Forcing SABnzbd to quit may damage your queues. - Some Usenet servers have intermittent login (or other) problems. For these the server blocking method is not very favourable. There is an INI-only option that will limit blocks to 1 minute. no_penalties = 1 See: https://sabnzbd.org/wiki/configuration/2.3/special - Some third-party utilties try to probe SABnzbd API in such a way that you will often see warnings about unauthenticated access. If you are sure these probes are harmless, you can suppress the warnings by setting the option "api_warnings" to 0. See: https://sabnzbd.org/wiki/configuration/2.3/special - On OSX you may encounter downloaded files with foreign characters. The par2 repair may fail when the files were created on a Windows system. The problem is caused by the PAR2 utility and we cannot fix this now. This does not apply to files inside RAR files. - On Linux when you download files they may have the wrong character encoding. You will see this only when downloaded files contain accented characters. You need to fix it yourself by running the convmv utility (available for most Linux platforms). Possible the file system override setting 'fsys_type' might be solve things: See: https://sabnzbd.org/wiki/configuration/2.3/special - The "Watched Folder" sometimes fails to delete the NZB files it has processed. This happens when other software still accesses these files. Some third-party utilities supporting SABnzbd are known to do this. We cannot solve this problem, because the Operating System (read Windows) prevents the removal. - Memory usage can sometimes have high peaks. This makes using SABnzbd on very low memory systems (e.g. a NAS device or a router) a challenge. In particular on Synology (SynoCommunity) the device may report that SABnzbd is using a lot of memory even when idle. In this case the memory is usually not actually used by SABnzbd and will be available if required by other apps or the system. More information can be found in the discussion here: https://github.com/SynoCommunity/spksrc/issues/2856 - SABnzbd is not compatible with some software firewall versions. The Microsoft Windows Firewall works fine, but remember to tell this firewall that SABnzbd is allowed to talk to other computers. - When SABnzbd cannot send notification emails, check your virus scanner, firewall or security suite. It may be blocking outgoing email. - When you are using external drives or network shares on OSX or Linux make sure that the drives are mounted. The operating system will simply redirect your files to alternative locations. You may have trouble finding the files when mounting the drive later. On OSX, SABnzbd will not create new folders in /Volumes. The result will be a failed job that can be retried once the volume has been mounted. - If you use a mounted drive as "temporary download folder", it must be present when SABnzbd starts up. If not, SABnzbd will use the default location. You can make SABnzbd wait for a mount of the "temporary download folder" by setting Config->Special->wait_for_dfolder to 1. SABnzbd will appear to hang until the drive is mounted. SABnzbd-2.3.2/LICENSE.txt0000644000000000000000000000143213217005256012753 0ustar 00000000000000(c) Copyright 2007-2017 by "The SABnzbd-team" This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. See accompanying files GPL2.txt and GPL3.txt.SABnzbd-2.3.2/PKG-INFO0000644000000000000000000000043513217004753012230 0ustar 00000000000000Metadata-Version: 1.0 Name: SABnzbd Version: 2.3.2 Summary: SABnzbd-2.3.2 Home-page: https://sabnzbd.org Author: The SABnzbd Team Author-email: team@sabnzbd.org License: GNU General Public License 2 (GPL2 or later) Description: Fully automated Usenet Binary Downloader Platform: posix SABnzbd-2.3.2/README.txt0000644000000000000000000000542313217004753012633 0ustar 00000000000000Release Notes - SABnzbd 2.3.2 ========================================================= ## Changes since 2.3.1 - SABYenc updated to 3.3.2 to fix rare crash during downloading - Minor updates of SABYenc (such as 3.3.2) are no longer mandatory - Article Cache is automatically set to 25% of system memory, if no custom value was set. Maximum set by auto-detect is 1GB - Simplify Config pages by hiding Advanced Settings - Added option '%dn' to Date Sorting to rename files as job name - Added 'Job Name as Folder Name' as Sorting Preset for de-obfuscation - Server usage graphs are now linked to make comparing servers easier - URLs that fail to fetch due to server errors will only be retried 10x - Delay between URL retries increases when not specified by server - First article of each file is downloaded first to identify filenames - Jobs finished by Direct Unpack will be post-processed first - If available, 7zip will be used instead of unzip - Job password entered by user is always shown in History - Password is also extracted from filename in case of custom job name - Add per-day download-statistics to 'server_stats' API-call - Added Hebrew date-time texts ## Bugfixes since 2.3.1 - Dropped connections could result in stalled downloads - Pre-queue scripts would fail to run - Pre-queue script output was not always parsed correctly - Notifications were always sent for 'Default' category - 'History Retention' also checked on start of program - macOS: Restore full compatibility with macOS 10.11 - Windows: Unpacking could fail due to paths not being quoted - Windows: All input parameters to scripts are now quoted - Windows: Complete folder in root of drive could crash post-processing - Windows: Automatically correct 'Extra Par2 Parameters' for MultiPar - Windows: Prevent potential pause/unpause loop after tray icon click ## Upgrading from 2.2.x and older - Finish queue - Stop SABnzbd - Install new version - Start SABnzbd ## Upgrade notices - When upgrading from 2.2.0 or older the queue will be converted. Job order, settings and data will be preserved, but all jobs will be unpaused and URL's that did not finish fetching before the upgrade will be lost. - The organization of the download queue is different from 0.7.x releases. This version will not see the 0.7.x queue, but you can restore the jobs by going to Status page and using Queue Repair. ## Known problems and solutions - Read the file "ISSUES.txt" ## About SABnzbd is an open-source cross-platform binary newsreader. It simplifies the process of downloading from Usenet dramatically, thanks to its web-based user interface and advanced built-in post-processing options that automatically verify, repair, extract and clean up posts downloaded from Usenet. (c) Copyright 2007-2017 by "The SABnzbd-team" \ SABnzbd-2.3.2/SABHelper.py0000644000000000000000000001223513217005257013253 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import sys if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0): print "Sorry, requires Python 2.6 or 2.7." sys.exit(1) import os import time import subprocess try: import win32api import win32file import win32serviceutil import win32evtlogutil import win32event import win32service import pywintypes except ImportError: print "Sorry, requires Python module PyWin32." sys.exit(1) from util.mailslot import MailSlot from util.apireg import del_connection_info, set_connection_info WIN_SERVICE = None def HandleCommandLine(allow_service=True): """ Handle command line for a Windows Service Prescribed name that will be called by Py2Exe. You MUST set 'cmdline_style':'custom' in the package.py! """ win32serviceutil.HandleCommandLine(SABHelper) def start_sab(): return subprocess.Popen('net start SABnzbd', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).stdout.read() def main(): mail = MailSlot() if not mail.create(10): return '- Cannot create Mailslot' active = False # SABnzbd should be running counter = 0 # Time allowed for SABnzbd to be silent while True: msg = mail.receive() if msg: if msg == 'restart': time.sleep(1.0) counter = 0 del_connection_info(user=False) start_sab() elif msg == 'stop': active = False del_connection_info(user=False) elif msg == 'active': active = True counter = 0 elif msg.startswith('api '): active = True counter = 0 _cmd, url = msg.split() if url: set_connection_info(url.strip(), user=False) if active: counter += 1 if counter > 120: # 120 seconds counter = 0 start_sab() rc = win32event.WaitForMultipleObjects((WIN_SERVICE.hWaitStop, WIN_SERVICE.overlapped.hEvent), 0, 1000) if rc == win32event.WAIT_OBJECT_0: del_connection_info(user=False) mail.disconnect() return '' ############################################################################## # Windows Service Support ############################################################################## import servicemanager class SABHelper(win32serviceutil.ServiceFramework): """ Win32 Service Handler """ _svc_name_ = 'SABHelper' _svc_display_name_ = 'SABnzbd Helper' _svc_deps_ = ["EventLog", "Tcpip"] _svc_description_ = 'Automated downloading from Usenet. ' \ 'This service helps SABnzbd to restart itself.' def __init__(self, args): global WIN_SERVICE win32serviceutil.ServiceFramework.__init__(self, args) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.overlapped = pywintypes.OVERLAPPED() # @UndefinedVariable self.overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) WIN_SERVICE = self def SvcDoRun(self): msg = 'SABHelper-service' self.Logger(servicemanager.PYS_SERVICE_STARTED, msg + ' has started') res = main() self.Logger(servicemanager.PYS_SERVICE_STOPPED, msg + ' has stopped' + res) def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) def Logger(self, state, msg): win32evtlogutil.ReportEvent(self._svc_display_name_, state, 0, servicemanager.EVENTLOG_INFORMATION_TYPE, (self._svc_name_, unicode(msg))) def ErrLogger(self, msg, text): win32evtlogutil.ReportEvent(self._svc_display_name_, servicemanager.PYS_SERVICE_STOPPED, 0, servicemanager.EVENTLOG_ERROR_TYPE, (self._svc_name_, unicode(msg)), unicode(text)) ############################################################################## # Platform specific startup code ############################################################################## if __name__ == '__main__': win32serviceutil.HandleCommandLine(SABHelper, argv=sys.argv) SABnzbd-2.3.2/SABnzbd.py0000755000000000000000000017444413217005257013007 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import sys if sys.version_info[:2] < (2, 7) or sys.version_info[:2] >= (3, 0): print "Sorry, requires Python 2.7." sys.exit(1) # Make sure UTF-8 is default 8bit encoding if not hasattr(sys, "setdefaultencoding"): reload(sys) try: sys.setdefaultencoding('utf-8') except: print 'Sorry, you MUST add the SABnzbd folder to the PYTHONPATH environment variable' print 'or find another way to force Python to use UTF-8 for text encoding.' sys.exit(1) import logging import logging.handlers import traceback import os import getopt import signal import socket import platform import ssl import time import re try: import Cheetah if Cheetah.Version[0] != '2': raise ValueError except ValueError: print "Sorry, requires Python module Cheetah 2.0rc7 or higher." sys.exit(1) except: print "The Python module Cheetah is required" sys.exit(1) import cherrypy if [int(n) for n in cherrypy.__version__.split('.')] < [8, 1, 2]: print 'Sorry, requires Python module Cherrypy 8.1.2+ (use the included version)' sys.exit(1) SQLITE_DLL = True try: from sqlite3 import version as sqlite3_version except: try: from pysqlite2.dbapi2 import version as sqlite3_version except: if os.name != 'nt': print "Sorry, requires Python module sqlite3" print "Try: apt-get install python-pysqlite2" sys.exit(1) else: SQLITE_DLL = False import locale import __builtin__ try: locale.setlocale(locale.LC_ALL, "") __builtin__.__dict__['codepage'] = locale.getlocale()[1] or 'cp1252' except: # Work-around for Python-ports with bad "locale" support __builtin__.__dict__['codepage'] = 'cp1252' import sabnzbd import sabnzbd.lang import sabnzbd.interface from sabnzbd.constants import * import sabnzbd.newsunpack from sabnzbd.misc import real_path, \ check_latest_version, exit_sab, get_from_url, \ split_host, get_ext, create_https_certificates, \ windows_variant, ip_extract, set_serv_parms, get_serv_parms, globber_full from sabnzbd.panic import panic_tmpl, panic_port, panic_host, \ panic_sqlite, panic, launch_a_browser import sabnzbd.scheduler as scheduler import sabnzbd.config as config import sabnzbd.cfg import sabnzbd.downloader from sabnzbd.encoding import unicoder, deunicode import sabnzbd.notifier as notifier import sabnzbd.zconfig from threading import Thread LOG_FLAG = False # Global for this module, signaling loglevel change try: import win32api import win32serviceutil import win32evtlogutil import win32event import win32service import pywintypes win32api.SetConsoleCtrlHandler(sabnzbd.sig_handler, True) from util.mailslot import MailSlot from util.apireg import get_connection_info, set_connection_info, del_connection_info except ImportError: class MailSlot: pass if sabnzbd.WIN32: print "Sorry, requires Python module PyWin32." sys.exit(1) def guard_loglevel(): """ Callback function for guarding loglevel """ global LOG_FLAG LOG_FLAG = True class guiHandler(logging.Handler): """ Logging handler collects the last warnings/errors/exceptions to be displayed in the web-gui """ def __init__(self, size): """ Initializes the handler """ logging.Handler.__init__(self) self.size = size self.store = [] def emit(self, record): """ Emit a record by adding it to our private queue """ if record.levelname == 'WARNING': sabnzbd.LAST_WARNING = record.msg % record.args else: sabnzbd.LAST_ERROR = record.msg % record.args if len(self.store) >= self.size: # Loose the oldest record self.store.pop(0) try: # Append traceback, if available warning = {'type': record.levelname, 'text': record.msg % record.args, 'time': int(time.time())} if record.exc_info: warning['text'] = '%s\n%s' % (warning['text'], traceback.format_exc()) self.store.append(warning) except UnicodeDecodeError: # Catch elusive Unicode conversion problems pass def clear(self): self.store = [] def count(self): return len(self.store) def content(self): """ Return an array with last records """ return self.store def print_help(): print print "Usage: %s [-f ] " % sabnzbd.MY_NAME print print "Options marked [*] are stored in the config file" print print "Options:" print " -f --config-file Location of config file" print " -s --server Listen on server:port [*]" print " -t --templates Template directory [*]" print print " -l --logging <0..2> Set logging level (-1=off, 0= least, 2= most) [*]" print " -w --weblogging Enable cherrypy access logging" print print " -b --browser <0..1> Auto browser launch (0= off, 1= on) [*]" if sabnzbd.WIN32: print " -d --daemon Use when run as a service" else: print " -d --daemon Fork daemon process" print " --pid Create a PID file in the given folder (full path)" print " --pidfile Create a PID file with the given name (full path)" print print " -h --help Print this message" print " -v --version Print version information" print " -c --clean Remove queue, cache and logs" print " -p --pause Start in paused mode" print " --repair Add orphaned jobs from the incomplete folder to the queue" print " --repair-all Try to reconstruct the queue from the incomplete folder" print " with full data reconstruction" print " --https Port to use for HTTPS server" print " --ipv6_hosting <0|1> Listen on IPv6 address [::1] [*]" print " --no-login Start with username and password reset" print " --log-all Log all article handling (for developers)" print " --console Force console logging for OSX app" print " --new Run a new instance of SABnzbd" def print_version(): print """ %s-%s Copyright (C) 2008-2017, The SABnzbd-Team SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. """ % (sabnzbd.MY_NAME, sabnzbd.__version__) def daemonize(): try: pid = os.fork() if pid > 0: sys.exit(0) except OSError: print "fork() failed" sys.exit(1) os.chdir(sabnzbd.DIR_PROG) os.setsid() # Make sure I can read my own files and shut out others prev = os.umask(0) os.umask(prev and int('077', 8)) try: pid = os.fork() if pid > 0: sys.exit(0) except OSError: print "fork() failed" sys.exit(1) dev_null = file('/dev/null', 'r') os.dup2(dev_null.fileno(), sys.stdin.fileno()) def Bail_Out(browserhost, cherryport, err=''): """ Abort program because of CherryPy troubles """ logging.error(T('Failed to start web-interface') + ' : ' + str(err)) if not sabnzbd.DAEMON: if '49' in err: panic_host(browserhost, cherryport) else: panic_port(browserhost, cherryport) sabnzbd.halt() exit_sab(2) def Web_Template(key, defweb, wdir): """ Determine a correct web template set, return full template path """ if wdir is None: try: wdir = fix_webname(key()) except: wdir = '' if not wdir: wdir = defweb if key: key.set(wdir) if not wdir: # No default value defined, accept empty path return '' full_dir = real_path(sabnzbd.DIR_INTERFACES, wdir) full_main = real_path(full_dir, DEF_MAIN_TMPL) logging.info("Web dir is %s", full_dir) if not os.path.exists(full_main): # end temp fix logging.warning(T('Cannot find web template: %s, trying standard template'), full_main) full_dir = real_path(sabnzbd.DIR_INTERFACES, DEF_STDINTF) full_main = real_path(full_dir, DEF_MAIN_TMPL) if not os.path.exists(full_main): logging.exception('Cannot find standard template: %s', full_dir) panic_tmpl(full_dir) exit_sab(1) return real_path(full_dir, "templates") def CheckColor(color, web_dir): """ Check existence of color-scheme """ if color and os.path.exists(os.path.join(web_dir, 'static/stylesheets/colorschemes/' + color + '.css')): return color elif color and os.path.exists(os.path.join(web_dir, 'static/stylesheets/colorschemes/' + color)): return color else: return '' def fix_webname(name): if name: name = deunicode(name) xname = name.title() else: xname = '' if xname in ('Default', ): return 'Glitter' elif xname in ('Glitter', 'Plush'): return xname elif xname in ('Smpl', 'Wizard'): return name.lower() elif xname in ('Config',): return 'Glitter' else: return name def GetProfileInfo(vista_plus): """ Get the default data locations """ ok = False if sabnzbd.DAEMON: # In daemon mode, do not try to access the user profile # just assume that everything defaults to the program dir sabnzbd.DIR_APPDATA = sabnzbd.DIR_PROG sabnzbd.DIR_LCLDATA = sabnzbd.DIR_PROG sabnzbd.DIR_HOME = sabnzbd.DIR_PROG if sabnzbd.WIN32: # Ignore Win32 "logoff" signal # This should work, but it doesn't # Instead the signal_handler will ignore the "logoff" signal # signal.signal(5, signal.SIG_IGN) pass ok = True elif sabnzbd.WIN32: try: from win32com.shell import shell, shellcon path = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, None, 0) sabnzbd.DIR_APPDATA = os.path.join(path, DEF_WORKDIR) path = shell.SHGetFolderPath(0, shellcon.CSIDL_LOCAL_APPDATA, None, 0) sabnzbd.DIR_LCLDATA = os.path.join(path, DEF_WORKDIR) sabnzbd.DIR_HOME = os.environ['USERPROFILE'] ok = True except: try: if vista_plus: root = os.environ['AppData'] user = os.environ['USERPROFILE'] sabnzbd.DIR_APPDATA = '%s\\%s' % (root.replace('\\Roaming', '\\Local'), DEF_WORKDIR) sabnzbd.DIR_HOME = user else: root = os.environ['USERPROFILE'] sabnzbd.DIR_APPDATA = '%s\\%s' % (root, DEF_WORKDIR) sabnzbd.DIR_HOME = root try: # Conversion to 8bit ASCII required for CherryPy sabnzbd.DIR_APPDATA = sabnzbd.DIR_APPDATA.encode(codepage) sabnzbd.DIR_HOME = sabnzbd.DIR_HOME.encode(codepage) ok = True except: # If unconvertible characters exist, use MSDOS name try: sabnzbd.DIR_APPDATA = win32api.GetShortPathName(sabnzbd.DIR_APPDATA) sabnzbd.DIR_HOME = win32api.GetShortPathName(sabnzbd.DIR_HOME) ok = True except: pass sabnzbd.DIR_LCLDATA = sabnzbd.DIR_APPDATA except: pass elif sabnzbd.DARWIN: home = os.environ.get('HOME') if home: sabnzbd.DIR_APPDATA = '%s/Library/Application Support/SABnzbd' % home sabnzbd.DIR_LCLDATA = sabnzbd.DIR_APPDATA sabnzbd.DIR_HOME = home ok = True else: # Unix/Linux home = os.environ.get('HOME') if home: sabnzbd.DIR_APPDATA = '%s/.%s' % (home, DEF_WORKDIR) sabnzbd.DIR_LCLDATA = sabnzbd.DIR_APPDATA sabnzbd.DIR_HOME = home ok = True if not ok: panic("Cannot access the user profile.", "Please start with sabnzbd.ini file in another location") exit_sab(2) def print_modules(): """ Log all detected optional or external modules """ if sabnzbd.decoder.SABYENC_ENABLED: # Yes, we have SABYenc, and it's the correct version, so it's enabled logging.info("SABYenc module (v%s)... found!", sabnzbd.decoder.SABYENC_VERSION) else: # Something wrong with SABYenc, so let's determine and print what: if sabnzbd.decoder.SABYENC_VERSION: # We have a VERSION, thus a SABYenc module, but it's not the correct version logging.warning(T("SABYenc disabled: no correct version found! (Found v%s, expecting v%s)") % (sabnzbd.decoder.SABYENC_VERSION, sabnzbd.constants.SABYENC_VERSION_REQUIRED)) else: # No SABYenc module at all logging.warning(T("SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc") % sabnzbd.constants.SABYENC_VERSION_REQUIRED) # No correct SABYenc version or no SABYenc at all, so now we care about old-yEnc if sabnzbd.decoder.HAVE_YENC: logging.info("_yenc module... found!") else: logging.error(T('_yenc module... NOT found!')) if sabnzbd.HAVE_CRYPTOGRAPHY: logging.info('Cryptography module (v%s)... found!', sabnzbd.HAVE_CRYPTOGRAPHY) else: logging.info('Cryptography module... NOT found!') if sabnzbd.newsunpack.PAR2_COMMAND: logging.info("par2 binary... found (%s)", sabnzbd.newsunpack.PAR2_COMMAND) else: logging.error('%s %s' % (T('par2 binary... NOT found!'), T('Verification and repair will not be possible.'))) if sabnzbd.newsunpack.MULTIPAR_COMMAND: logging.info("MultiPar binary... found (%s)", sabnzbd.newsunpack.MULTIPAR_COMMAND) elif sabnzbd.WIN32: logging.error('%s %s' % (T('MultiPar binary... NOT found!'), T('Verification and repair will not be possible.'))) if sabnzbd.newsunpack.RAR_COMMAND: logging.info("UNRAR binary... found (%s)", sabnzbd.newsunpack.RAR_COMMAND) # Report problematic unrar if sabnzbd.newsunpack.RAR_PROBLEM and not sabnzbd.cfg.ignore_wrong_unrar(): have_str = '%.2f' % (float(sabnzbd.newsunpack.RAR_VERSION) / 100) want_str = '%.2f' % (float(sabnzbd.constants.REC_RAR_VERSION) / 100) logging.warning(T('Your UNRAR version is %s, we recommend version %s or higher.
') % (have_str, want_str)) elif not (sabnzbd.WIN32 or sabnzbd.DARWIN): logging.info('UNRAR binary version %.2f', (float(sabnzbd.newsunpack.RAR_VERSION) / 100)) else: logging.error('%s %s' % (T('unrar binary... NOT found'), T('Downloads will not unpacked.'))) if sabnzbd.newsunpack.ZIP_COMMAND: logging.info("unzip binary... found (%s)", sabnzbd.newsunpack.ZIP_COMMAND) else: logging.info(T('unzip binary... NOT found!')) if sabnzbd.newsunpack.SEVEN_COMMAND: logging.info("7za binary... found (%s)", sabnzbd.newsunpack.SEVEN_COMMAND) else: logging.info(T('7za binary... NOT found!')) if not sabnzbd.WIN32: if sabnzbd.newsunpack.NICE_COMMAND: logging.info("nice binary... found (%s)", sabnzbd.newsunpack.NICE_COMMAND) else: logging.info("nice binary... NOT found!") if sabnzbd.newsunpack.IONICE_COMMAND: logging.info("ionice binary... found (%s)", sabnzbd.newsunpack.IONICE_COMMAND) else: logging.info("ionice binary... NOT found!") def all_localhosts(): """ Return all unique values of localhost in order of preference """ ips = ['127.0.0.1'] try: # Check whether IPv6 is available and enabled info = socket.getaddrinfo('::1', None) af, socktype, proto, _canonname, _sa = info[0] s = socket.socket(af, socktype, proto) s.close() except socket.error: return ips try: info = socket.getaddrinfo('localhost', None) except: # localhost does not resolve return ips ips = [] for item in info: item = item[4][0] # Avoid problems on strange Linux settings if not isinstance(item, basestring): continue # Only return IPv6 when enabled if item not in ips and ('::1' not in item or sabnzbd.cfg.ipv6_hosting()): ips.append(item) return ips def check_resolve(host): """ Return True if 'host' resolves """ try: dummy = socket.getaddrinfo(host, None) except: # Does not resolve return False return True def get_webhost(cherryhost, cherryport, https_port): """ Determine the webhost address and port, return (host, port, browserhost) """ if cherryhost == '0.0.0.0' and not check_resolve('127.0.0.1'): cherryhost = '' elif cherryhost == '::' and not check_resolve('::1'): cherryhost = '' if cherryhost is None: cherryhost = deunicode(sabnzbd.cfg.cherryhost()) else: sabnzbd.cfg.cherryhost.set(cherryhost) # Get IP address, but discard APIPA/IPV6 # If only APIPA's or IPV6 are found, fall back to localhost ipv4 = ipv6 = False localhost = hostip = 'localhost' try: info = socket.getaddrinfo(socket.gethostname(), None) except: # Hostname does not resolve try: # Valid user defined name? info = socket.getaddrinfo(cherryhost, None) except: if cherryhost not in ('localhost', '127.0.0.1', '::1'): cherryhost = '0.0.0.0' try: info = socket.getaddrinfo(localhost, None) except: info = socket.getaddrinfo('127.0.0.1', None) localhost = '127.0.0.1' for item in info: ip = str(item[4][0]) if ip.startswith('169.254.'): pass # Automatic Private IP Addressing (APIPA) elif ':' in ip: ipv6 = True elif '.' in ip and not ipv4: ipv4 = True hostip = ip # A blank host will use the local ip address if cherryhost == '': if ipv6 and ipv4: # To protect Firefox users, use numeric IP cherryhost = hostip browserhost = hostip else: cherryhost = socket.gethostname() browserhost = cherryhost # 0.0.0.0 will listen on all ipv4 interfaces (no ipv6 addresses) elif cherryhost == '0.0.0.0': # Just take the gamble for this cherryhost = '0.0.0.0' browserhost = localhost # :: will listen on all ipv6 interfaces (no ipv4 addresses) elif cherryhost in ('::', '[::]'): cherryhost = cherryhost.strip('[').strip(']') # Assume '::1' == 'localhost' browserhost = localhost # IPV6 address elif '[' in cherryhost or ':' in cherryhost: browserhost = cherryhost # IPV6 numeric address elif cherryhost.replace('.', '').isdigit(): # IPV4 numerical browserhost = cherryhost elif cherryhost == localhost: cherryhost = localhost browserhost = localhost else: # If on Vista and/or APIPA, use numerical IP, to help FireFoxers if ipv6 and ipv4: cherryhost = hostip browserhost = cherryhost # Some systems don't like brackets in numerical ipv6 if sabnzbd.DARWIN: cherryhost = cherryhost.strip('[]') else: try: info = socket.getaddrinfo(cherryhost, None) except: cherryhost = cherryhost.strip('[]') if ipv6 and ipv4 and \ (browserhost not in ('localhost', '127.0.0.1', '[::1]', '::1')): sabnzbd.AMBI_LOCALHOST = True logging.info("IPV6 has priority on this system, potential Firefox issue") if ipv6 and ipv4 and cherryhost == '' and sabnzbd.WIN32: logging.warning(T('Please be aware the 0.0.0.0 hostname will need an IPv6 address for external access')) if cherryhost == 'localhost' and not sabnzbd.WIN32 and not sabnzbd.DARWIN: # On the Ubuntu family, localhost leads to problems for CherryPy ips = ip_extract() if '127.0.0.1' in ips and '::1' in ips: cherryhost = '127.0.0.1' if ips[0] != '127.0.0.1': browserhost = '127.0.0.1' # This is to please Chrome on OSX if cherryhost == 'localhost' and sabnzbd.DARWIN: cherryhost = '127.0.0.1' browserhost = 'localhost' if cherryport is None: cherryport = sabnzbd.cfg.cherryport.get_int() else: sabnzbd.cfg.cherryport.set(str(cherryport)) if https_port is None: https_port = sabnzbd.cfg.https_port.get_int() else: sabnzbd.cfg.https_port.set(str(https_port)) # if the https port was specified, assume they want HTTPS enabling also sabnzbd.cfg.enable_https.set(True) if cherryport == https_port and sabnzbd.cfg.enable_https(): sabnzbd.cfg.enable_https.set(False) # Should have a translated message, but that's not available yet logging.error(T('HTTP and HTTPS ports cannot be the same')) return cherryhost, cherryport, browserhost, https_port def attach_server(host, port, cert=None, key=None, chain=None): """ Define and attach server, optionally HTTPS """ if sabnzbd.cfg.ipv6_hosting() or '::1' not in host: http_server = cherrypy._cpserver.Server() http_server.bind_addr = (host, port) if cert and key: http_server.ssl_module = 'builtin' http_server.ssl_certificate = cert http_server.ssl_private_key = key http_server.ssl_certificate_chain = chain http_server.subscribe() def is_sabnzbd_running(url): """ Return True when there's already a SABnzbd instance running. """ try: url = '%s&mode=version' % (url) # Do this without certificate verification, few installations will have that prev = sabnzbd.set_https_verification(False) ver = get_from_url(url) sabnzbd.set_https_verification(prev) return (ver and (re.search(r'\d+\.\d+\.', ver) or ver.strip() == sabnzbd.__version__)) except: return False def find_free_port(host, currentport): """ Return a free port, 0 when nothing is free """ n = 0 while n < 10 and currentport <= 49151: try: cherrypy.process.servers.check_port(host, currentport, timeout=0.025) return currentport except: currentport += 5 n += 1 return 0 def check_for_sabnzbd(url, upload_nzbs, allow_browser=True): """ Check for a running instance of sabnzbd on this port allow_browser==True|None will launch the browser, False will not. """ if allow_browser is None: allow_browser = True if is_sabnzbd_running(url): # Upload any specified nzb files to the running instance if upload_nzbs: from sabnzbd.utils.upload import upload_file prev = sabnzbd.set_https_verification(0) for f in upload_nzbs: upload_file(url, f) sabnzbd.set_https_verification(prev) else: # Launch the web browser and quit since sabnzbd is already running # Trim away everything after the final slash in the URL url = url[:url.rfind('/') + 1] launch_a_browser(url, force=allow_browser) exit_sab(0) return True return False def evaluate_inipath(path): """ Derive INI file path from a partial path. Full file path: if file does not exist the name must contain a dot but not a leading dot. foldername is enough, the standard name will be appended. """ if sabnzbd.WIN32: path = unicoder(path) path = os.path.normpath(os.path.abspath(path)) inipath = os.path.join(path, DEF_INI_FILE) if os.path.isdir(path): return inipath elif os.path.isfile(path) or os.path.isfile(path + '.bak'): return path else: _dirpart, name = os.path.split(path) if name.find('.') < 1: return inipath else: return path def commandline_handler(frozen=True): """ Split win32-service commands are true parameters Returns: service, sab_opts, serv_opts, upload_nzbs """ service = '' sab_opts = [] serv_opts = [os.path.normpath(os.path.abspath(sys.argv[0]))] upload_nzbs = [] # OSX binary: get rid of the weird -psn_0_123456 parameter for arg in sys.argv: if arg.startswith('-psn_'): sys.argv.remove(arg) break # Ugly hack to remove the extra "SABnzbd*" parameter the Windows binary # gets when it's restarted if len(sys.argv) > 1 and \ 'sabnzbd' in sys.argv[1].lower() and \ not sys.argv[1].startswith('-'): slice = 2 else: slice = 1 # Prepend options from env-variable to options info = os.environ.get('SABnzbd', '').split() info.extend(sys.argv[slice:]) try: opts, args = getopt.getopt(info, "phdvncwl:s:f:t:b:2:", ['pause', 'help', 'daemon', 'nobrowser', 'clean', 'logging=', 'weblogging', 'server=', 'templates', 'ipv6_hosting=', 'template2', 'browser=', 'config-file=', 'force', 'version', 'https=', 'autorestarted', 'repair', 'repair-all', 'log-all', 'no-login', 'pid=', 'new', 'console', 'pidfile=', # Below Win32 Service options 'password=', 'username=', 'startup=', 'perfmonini=', 'perfmondll=', 'interactive', 'wait=', ]) except getopt.GetoptError: print_help() exit_sab(2) # Check for Win32 service commands if args and args[0] in ('install', 'update', 'remove', 'start', 'stop', 'restart', 'debug'): service = args[0] serv_opts.extend(args) if not service: # Get and remove any NZB file names for entry in args: if get_ext(entry) in ('.nzb', '.zip', '.rar', '.gz', '.bz2'): upload_nzbs.append(os.path.abspath(entry)) for opt, arg in opts: if opt in ('password', 'username', 'startup', 'perfmonini', 'perfmondll', 'interactive', 'wait'): # Service option, just collect if service: serv_opts.append(opt) if arg: serv_opts.append(arg) else: if opt == '-f': arg = os.path.normpath(os.path.abspath(arg)) sab_opts.append((opt, arg)) return service, sab_opts, serv_opts, upload_nzbs def get_f_option(opts): """ Return value of the -f option """ for opt, arg in opts: if opt == '-f': return arg else: return None def main(): global LOG_FLAG import sabnzbd # Due to ApplePython bug autobrowser = None autorestarted = False sabnzbd.MY_FULLNAME = sys.argv[0] sabnzbd.MY_NAME = os.path.basename(sabnzbd.MY_FULLNAME) fork = False pause = False inifile = None cherryhost = None cherryport = None https_port = None cherrypylogging = None clean_up = False logging_level = None web_dir = None vista_plus = False win64 = False repair = 0 api_url = None no_login = False sabnzbd.RESTART_ARGS = [sys.argv[0]] pid_path = None pid_file = None new_instance = False osx_console = False ipv6_hosting = None _service, sab_opts, _serv_opts, upload_nzbs = commandline_handler() for opt, arg in sab_opts: if opt == '--servicecall': sabnzbd.MY_FULLNAME = arg elif opt in ('-d', '--daemon'): if not sabnzbd.WIN32: fork = True autobrowser = False sabnzbd.DAEMON = True sabnzbd.RESTART_ARGS.append(opt) elif opt in ('-f', '--config-file'): inifile = arg sabnzbd.RESTART_ARGS.append(opt) sabnzbd.RESTART_ARGS.append(arg) elif opt in ('-h', '--help'): print_help() exit_sab(0) elif opt in ('-t', '--templates'): web_dir = arg elif opt in ('-s', '--server'): (cherryhost, cherryport) = split_host(arg) elif opt in ('-n', '--nobrowser'): autobrowser = False elif opt in ('-b', '--browser'): try: autobrowser = bool(int(arg)) except: autobrowser = True elif opt in ('--autorestarted', ): autorestarted = True elif opt in ('-c', '--clean'): clean_up = True elif opt in ('-w', '--weblogging'): cherrypylogging = True elif opt in ('-l', '--logging'): try: logging_level = int(arg) except: logging_level = -2 if logging_level < -1 or logging_level > 2: print_help() exit_sab(1) elif opt in ('-v', '--version'): print_version() exit_sab(0) elif opt in ('-p', '--pause'): pause = True elif opt in ('--https',): https_port = int(arg) sabnzbd.RESTART_ARGS.append(opt) sabnzbd.RESTART_ARGS.append(arg) elif opt in ('--repair',): repair = 1 pause = True elif opt in ('--repair-all',): repair = 2 pause = True elif opt in ('--log-all',): sabnzbd.LOG_ALL = True elif opt in ('--no-login',): no_login = True elif opt in ('--pid',): pid_path = arg sabnzbd.RESTART_ARGS.append(opt) sabnzbd.RESTART_ARGS.append(arg) elif opt in ('--pidfile',): pid_file = arg sabnzbd.RESTART_ARGS.append(opt) sabnzbd.RESTART_ARGS.append(arg) elif opt in ('--new',): new_instance = True elif opt in ('--console',): sabnzbd.RESTART_ARGS.append(opt) osx_console = True elif opt in ('--ipv6_hosting',): ipv6_hosting = arg sabnzbd.MY_FULLNAME = os.path.normpath(os.path.abspath(sabnzbd.MY_FULLNAME)) sabnzbd.MY_NAME = os.path.basename(sabnzbd.MY_FULLNAME) sabnzbd.DIR_PROG = os.path.dirname(sabnzbd.MY_FULLNAME) sabnzbd.DIR_INTERFACES = real_path(sabnzbd.DIR_PROG, DEF_INTERFACES) sabnzbd.DIR_LANGUAGE = real_path(sabnzbd.DIR_PROG, DEF_LANGUAGE) org_dir = os.getcwd() if getattr(sys, 'frozen', None) == 'macosx_app': # Correct path if frozen with py2app (OSX) sabnzbd.MY_FULLNAME = sabnzbd.MY_FULLNAME.replace("/Resources/SABnzbd.py", "/MacOS/SABnzbd") # Need console logging for SABnzbd.py and SABnzbd-console.exe consoleLogging = (not hasattr(sys, "frozen")) or (sabnzbd.MY_NAME.lower().find('-console') > 0) consoleLogging = consoleLogging and not sabnzbd.DAEMON # No console logging needed for OSX app noConsoleLoggingOSX = (not osx_console) and (sabnzbd.DIR_PROG.find('.app/Contents/Resources') > 0) if noConsoleLoggingOSX: consoleLogging = 1 LOGLEVELS = (logging.FATAL, logging.WARNING, logging.INFO, logging.DEBUG) # Setup primary logging to prevent default console logging gui_log = guiHandler(MAX_WARNINGS) gui_log.setLevel(logging.WARNING) format_gui = '%(asctime)s\n%(levelname)s\n%(message)s' gui_log.setFormatter(logging.Formatter(format_gui)) sabnzbd.GUIHANDLER = gui_log # Create logger logger = logging.getLogger('') logger.setLevel(logging.WARNING) logger.addHandler(gui_log) # Detect Windows variant if sabnzbd.WIN32: vista_plus, win64 = windows_variant() sabnzbd.WIN64 = win64 if not SQLITE_DLL: panic_sqlite(sabnzbd.MY_FULLNAME) exit_sab(2) if inifile: # INI file given, simplest case inifile = evaluate_inipath(inifile) else: # No ini file given, need profile data GetProfileInfo(vista_plus) # Find out where INI file is inifile = os.path.abspath(sabnzbd.DIR_LCLDATA + '/' + DEF_INI_FILE) # If INI file at non-std location, then use INI location as $HOME if sabnzbd.DIR_LCLDATA != os.path.dirname(inifile): sabnzbd.DIR_HOME = os.path.dirname(inifile) # All system data dirs are relative to the place we found the INI file sabnzbd.DIR_LCLDATA = os.path.dirname(inifile) if not os.path.exists(inifile) and not os.path.exists(inifile + '.bak') and not os.path.exists(sabnzbd.DIR_LCLDATA): try: os.makedirs(sabnzbd.DIR_LCLDATA) except IOError: panic('Cannot create folder "%s".' % sabnzbd.DIR_LCLDATA, 'Check specified INI file location.') exit_sab(1) sabnzbd.cfg.set_root_folders(sabnzbd.DIR_HOME, sabnzbd.DIR_LCLDATA) res, msg = config.read_config(inifile) if not res: panic(msg, 'Specify a correct file or delete this file.') exit_sab(1) # Set root folders for HTTPS server file paths sabnzbd.cfg.set_root_folders2() if ipv6_hosting is not None: sabnzbd.cfg.ipv6_hosting.set(ipv6_hosting) # Determine web host address cherryhost, cherryport, browserhost, https_port = get_webhost(cherryhost, cherryport, https_port) enable_https = sabnzbd.cfg.enable_https() # When this is a daemon, just check and bail out if port in use if sabnzbd.DAEMON: if enable_https and https_port: try: cherrypy.process.servers.check_port(cherryhost, https_port, timeout=0.05) except IOError, error: Bail_Out(browserhost, cherryport) except: Bail_Out(browserhost, cherryport, '49') try: cherrypy.process.servers.check_port(cherryhost, cherryport, timeout=0.05) except IOError, error: Bail_Out(browserhost, cherryport) except: Bail_Out(browserhost, cherryport, '49') # Windows instance is reachable through registry url = None if sabnzbd.WIN32 and not new_instance: url = get_connection_info() if url and check_for_sabnzbd(url, upload_nzbs, autobrowser): exit_sab(0) # SSL if enable_https: port = https_port or cherryport try: cherrypy.process.servers.check_port(browserhost, port, timeout=0.05) except IOError, error: if str(error) == 'Port not bound.': pass else: if not url: url = 'https://%s:%s%s/api?' % (browserhost, port, sabnzbd.cfg.url_base()) if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser): # Bail out if we have fixed our ports after first start-up if sabnzbd.cfg.fixed_ports(): Bail_Out(browserhost, cherryport) # Find free port to bind newport = find_free_port(browserhost, port) if newport > 0: # Save the new port if https_port: https_port = newport sabnzbd.cfg.https_port.set(newport) else: # In case HTTPS == HTTP port cherryport = newport sabnzbd.cfg.port.set(newport) except: # Something else wrong, probably badly specified host Bail_Out(browserhost, cherryport, '49') # NonSSL check if there's no HTTPS or we only use 1 port if not (enable_https and not https_port): try: cherrypy.process.servers.check_port(browserhost, cherryport, timeout=0.05) except IOError, error: if str(error) == 'Port not bound.': pass else: if not url: url = 'http://%s:%s%s/api?' % (browserhost, cherryport, sabnzbd.cfg.url_base()) if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser): # Bail out if we have fixed our ports after first start-up if sabnzbd.cfg.fixed_ports(): Bail_Out(browserhost, cherryport) # Find free port to bind port = find_free_port(browserhost, cherryport) if port > 0: sabnzbd.cfg.cherryport.set(port) cherryport = port except: # Something else wrong, probably badly specified host Bail_Out(browserhost, cherryport, '49') # We found a port, now we never check again sabnzbd.cfg.fixed_ports.set(True) if logging_level is None: logging_level = sabnzbd.cfg.log_level() else: sabnzbd.cfg.log_level.set(logging_level) logdir = sabnzbd.cfg.log_dir.get_path() if fork and not logdir: print "Error:" print "I refuse to fork without a log directory!" sys.exit(1) if clean_up: xlist = globber_full(logdir) for x in xlist: if RSS_FILE_NAME not in x: try: os.remove(x) except: pass # Prevent the logger from raising exceptions # primarily to reduce the fallout of Python issue 4749 logging.raiseExceptions = 0 sabnzbd.LOGFILE = os.path.join(logdir, DEF_LOG_FILE) try: rollover_log = logging.handlers.RotatingFileHandler( sabnzbd.LOGFILE, 'a+', sabnzbd.cfg.log_size.get_int(), sabnzbd.cfg.log_backups()) logformat = '%(asctime)s::%(levelname)s::[%(module)s:%(lineno)d] %(message)s' rollover_log.setFormatter(logging.Formatter(logformat)) sabnzbd.LOGHANDLER = rollover_log logger.addHandler(rollover_log) logger.setLevel(LOGLEVELS[logging_level + 1]) except IOError: print "Error:" print "Can't write to logfile" exit_sab(2) if fork: try: x = sys.stderr.fileno x = sys.stdout.fileno ol_path = os.path.join(logdir, DEF_LOG_ERRFILE) out_log = file(ol_path, 'a+', 0) sys.stderr.flush() sys.stdout.flush() os.dup2(out_log.fileno(), sys.stderr.fileno()) os.dup2(out_log.fileno(), sys.stdout.fileno()) except AttributeError: pass else: try: x = sys.stderr.fileno x = sys.stdout.fileno if consoleLogging: console = logging.StreamHandler() console.setLevel(LOGLEVELS[logging_level + 1]) console.setFormatter(logging.Formatter(logformat)) logger.addHandler(console) if noConsoleLoggingOSX: logging.info('Console logging for OSX App disabled') so = file('/dev/null', 'a+') os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(so.fileno(), sys.stderr.fileno()) except AttributeError: pass logging.info('--------------------------------') logging.info('%s-%s (rev=%s)', sabnzbd.MY_NAME, sabnzbd.__version__, sabnzbd.__baseline__) logging.info('Full executable path = %s', sabnzbd.MY_FULLNAME) if sabnzbd.WIN32: suffix = '' if win64: suffix = '(win64)' try: logging.info('Platform = %s %s', platform.platform(), suffix) except: logging.info('Platform = %s ', suffix) else: logging.info('Platform = %s', os.name) logging.info('Python-version = %s', sys.version) logging.info('Arguments = %s', sabnzbd.CMDLINE) # Find encoding; relevant for unrar activities try: preferredencoding = locale.getpreferredencoding() logging.info('Preferred encoding = %s', preferredencoding) except: logging.info('Preferred encoding = ERROR') preferredencoding = '' # On Linux/FreeBSD/Unix "UTF-8" is strongly, strongly adviced: if not sabnzbd.WIN32 and not sabnzbd.DARWIN and not ('utf' in preferredencoding.lower() and '8' in preferredencoding.lower()): logging.warning(T("SABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.") % preferredencoding) # SSL Information logging.info("SSL version = %s", ssl.OPENSSL_VERSION) # Load (extra) certificates in the binary distributions if hasattr(sys, "frozen") and (sabnzbd.WIN32 or sabnzbd.DARWIN): # The certifi package brings the latest certificates on build # This will cause the create_default_context to load it automatically os.environ["SSL_CERT_FILE"] = os.path.join(sabnzbd.DIR_PROG, 'cacert.pem') logging.info('Loaded additional certificates from %s', os.environ["SSL_CERT_FILE"]) # Extra startup info if sabnzbd.cfg.log_level() > 1: # List the number of certificates available (can take up to 1.5 seconds) if sabnzbd.HAVE_SSL_CONTEXT: ctx = ssl.create_default_context() logging.debug('Available certificates: %s', repr(ctx.cert_store_stats())) # Show IPv4/IPv6 address from sabnzbd.getipaddress import localipv4, publicipv4, ipv6 mylocalipv4 = localipv4() if mylocalipv4: logging.debug('My local IPv4 address = %s', mylocalipv4) else: logging.debug('Could not determine my local IPv4 address') mypublicipv4 = publicipv4() if mypublicipv4: logging.debug('My public IPv4 address = %s', mypublicipv4) else: logging.debug('Could not determine my public IPv4 address') myipv6 = ipv6() if myipv6: logging.debug('My IPv6 address = %s', myipv6) else: logging.debug('Could not determine my IPv6 address') # Measure and log system performance measured by pystone and - if possible - CPU model from sabnzbd.utils.getperformance import getpystone, getcpu pystoneperf = getpystone() if pystoneperf: logging.debug('CPU Pystone available performance = %s', pystoneperf) else: logging.debug('CPU Pystone available performance could not be calculated') cpumodel = getcpu() # Linux only if cpumodel: logging.debug('CPU model = %s', cpumodel) logging.info('Read INI file %s', inifile) if autobrowser is not None: sabnzbd.cfg.autobrowser.set(autobrowser) else: autobrowser = sabnzbd.cfg.autobrowser() if not sabnzbd.WIN_SERVICE and not getattr(sys, 'frozen', None) == 'macosx_app': signal.signal(signal.SIGINT, sabnzbd.sig_handler) signal.signal(signal.SIGTERM, sabnzbd.sig_handler) sabnzbd.initialize(pause, clean_up, evalSched=True, repair=repair) os.chdir(sabnzbd.DIR_PROG) sabnzbd.WEB_DIR = Web_Template(sabnzbd.cfg.web_dir, DEF_STDINTF, fix_webname(web_dir)) sabnzbd.WEB_DIR_CONFIG = Web_Template(None, DEF_STDCONFIG, '') sabnzbd.WIZARD_DIR = os.path.join(sabnzbd.DIR_INTERFACES, 'wizard') sabnzbd.WEB_COLOR = CheckColor(sabnzbd.cfg.web_color(), sabnzbd.WEB_DIR) sabnzbd.cfg.web_color.set(sabnzbd.WEB_COLOR) if fork and not sabnzbd.WIN32: daemonize() # Save the INI file config.save_config(force=True) if sabnzbd.cfg.win_menu() and not sabnzbd.DAEMON: if sabnzbd.WIN32: import sabnzbd.sabtray sabnzbd.WINTRAY = sabnzbd.sabtray.SABTrayThread() elif sabnzbd.LINUX_POWER and os.environ.get('DISPLAY'): try: import gtk import sabnzbd.sabtraylinux sabnzbd.LINUXTRAY = sabnzbd.sabtraylinux.StatusIcon() except: logging.info("pygtk2 not found. No SysTray.") # Find external programs sabnzbd.newsunpack.find_programs(sabnzbd.DIR_PROG) print_modules() # HTTPS certificate generation https_cert = sabnzbd.cfg.https_cert.get_path() https_key = sabnzbd.cfg.https_key.get_path() https_chain = sabnzbd.cfg.https_chain.get_path() if not (sabnzbd.cfg.https_chain() and os.path.exists(https_chain)): https_chain = None if enable_https: # If either the HTTPS certificate or key do not exist, make some self-signed ones. if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)): create_https_certificates(https_cert, https_key) if not (os.path.exists(https_cert) and os.path.exists(https_key)): logging.warning(T('Disabled HTTPS because of missing CERT and KEY files')) enable_https = False # Starting of the webserver # Determine if this system has multiple definitions for 'localhost' hosts = all_localhosts() multilocal = len(hosts) > 1 and cherryhost in ('localhost', '0.0.0.0') # For 0.0.0.0 CherryPy will always pick IPv4, so make sure the secondary localhost is IPv6 if multilocal and cherryhost == '0.0.0.0' and hosts[1] == '127.0.0.1': hosts[1] = '::1' # The Windows binary requires numeric localhost as primary address if cherryhost == 'localhost': cherryhost = hosts[0] if enable_https: if https_port: # Extra HTTP port for primary localhost attach_server(cherryhost, cherryport) if multilocal: # Extra HTTP port for secondary localhost attach_server(hosts[1], cherryport) # Extra HTTPS port for secondary localhost attach_server(hosts[1], https_port, https_cert, https_key, https_chain) cherryport = https_port elif multilocal: # Extra HTTPS port for secondary localhost attach_server(hosts[1], cherryport, https_cert, https_key, https_chain) cherrypy.config.update({'server.ssl_module': 'builtin', 'server.ssl_certificate': https_cert, 'server.ssl_private_key': https_key, 'server.ssl_certificate_chain': https_chain}) elif multilocal: # Extra HTTP port for secondary localhost attach_server(hosts[1], cherryport) if no_login: sabnzbd.cfg.username.set('') sabnzbd.cfg.password.set('') mime_gzip = ('text/*', 'application/javascript', 'application/x-javascript', 'application/json', 'application/xml', 'application/vnd.ms-fontobject', 'application/font*', 'image/svg+xml' ) cherrypy.config.update({'server.environment': 'production', 'server.socket_host': cherryhost, 'server.socket_port': cherryport, 'server.shutdown_timeout': 0, 'log.screen': False, 'engine.timeout_monitor.on': False, 'engine.autoreload.on': False, 'tools.encode.on': True, 'tools.gzip.on': True, 'tools.gzip.mime_types': mime_gzip, 'request.show_tracebacks': True, 'error_page.401': sabnzbd.panic.error_page_401, 'error_page.404': sabnzbd.panic.error_page_404 }) # Do we want CherryPy Logging? Cannot be done via the config if cherrypylogging: sabnzbd.WEBLOGFILE = os.path.join(logdir, DEF_LOG_CHERRY) cherrypy.log.screen = True cherrypy.log.access_log.propagate = True cherrypy.log.access_file = str(sabnzbd.WEBLOGFILE) else: cherrypy.log.access_log.propagate = False # Force mimetypes (OS might overwrite them) forced_mime_types = {'css': 'text/css', 'js': 'application/javascript'} static = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(sabnzbd.WEB_DIR, 'static'), 'tools.staticdir.content_types': forced_mime_types} staticcfg = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(sabnzbd.WEB_DIR_CONFIG, 'staticcfg'), 'tools.staticdir.content_types': forced_mime_types} wizard_static = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(sabnzbd.WIZARD_DIR, 'static'), 'tools.staticdir.content_types': forced_mime_types} appconfig = {'/api': {'tools.basic_auth.on': False}, '/rss': {'tools.basic_auth.on': False}, '/static': static, '/wizard/static': wizard_static, '/favicon.ico': {'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(sabnzbd.WEB_DIR_CONFIG, 'staticcfg', 'ico', 'favicon.ico')}, '/staticcfg': staticcfg } # Make available from both URLs main_page = sabnzbd.interface.MainPage() cherrypy.tree.mount(main_page, '/', config=appconfig) cherrypy.tree.mount(main_page, sabnzbd.cfg.url_base(), config=appconfig) # Set authentication for CherryPy sabnzbd.interface.set_auth(cherrypy.config) logging.info('Starting web-interface on %s:%s', cherryhost, cherryport) sabnzbd.cfg.log_level.callback(guard_loglevel) try: cherrypy.engine.start() except: logging.error(T('Failed to start web-interface: '), exc_info=True) Bail_Out(browserhost, cherryport) # Wait for server to become ready cherrypy.engine.wait(cherrypy.process.wspbus.states.STARTED) # Window Service support mail = None if sabnzbd.WIN32: if enable_https: mode = 's' else: mode = '' api_url = 'http%s://%s:%s%s/api?apikey=%s' % (mode, browserhost, cherryport, sabnzbd.cfg.url_base(), sabnzbd.cfg.api_key()) if sabnzbd.WIN_SERVICE: mail = MailSlot() if mail.connect(): logging.info('Connected to the SABHelper service') mail.send('api %s' % api_url) else: logging.error(T('Cannot reach the SABHelper service')) mail = None else: # Write URL directly to registry set_connection_info(api_url) if pid_path or pid_file: sabnzbd.pid_file(pid_path, pid_file, cherryport) # Start all SABnzbd tasks logging.info('Starting %s-%s', sabnzbd.MY_NAME, sabnzbd.__version__) try: sabnzbd.start() except: logging.exception("Failed to start %s-%s", sabnzbd.MY_NAME, sabnzbd.__version__) sabnzbd.halt() # Upload any nzb/zip/rar/nzb.gz/nzb.bz2 files from file association if upload_nzbs: from sabnzbd.utils.upload import add_local for f in upload_nzbs: add_local(f) # Set URL for browser if enable_https: browser_url = "https://%s:%s%s" % (browserhost, cherryport, sabnzbd.cfg.url_base()) else: browser_url = "http://%s:%s%s" % (browserhost, cherryport, sabnzbd.cfg.url_base()) sabnzbd.BROWSER_URL = browser_url if not autorestarted: launch_a_browser(browser_url) if sabnzbd.FOUNDATION: import sabnzbd.osxmenu sabnzbd.osxmenu.notify("SAB_Launched", None) notifier.send_notification('SABnzbd%s' % notifier.hostname(), T('SABnzbd %s started') % sabnzbd.__version__, 'startup') # Now's the time to check for a new version check_latest_version() autorestarted = False # ZeroConfig/Bonjour needs a ip. Lets try to find it. try: z_host = socket.gethostbyname(socket.gethostname()) except socket.gaierror: z_host = cherryhost sabnzbd.zconfig.set_bonjour(z_host, cherryport) # Have to keep this running, otherwise logging will terminate timer = 0 while not sabnzbd.SABSTOP: if sabnzbd.LAST_WARNING: msg = sabnzbd.LAST_WARNING sabnzbd.LAST_WARNING = None sabnzbd.notifier.send_notification(T('Warning'), msg, 'warning') if sabnzbd.LAST_ERROR: msg = sabnzbd.LAST_ERROR sabnzbd.LAST_ERROR = None sabnzbd.notifier.send_notification(T('Error'), msg, 'error') if sabnzbd.WIN_SERVICE: rc = win32event.WaitForMultipleObjects((sabnzbd.WIN_SERVICE.hWaitStop, sabnzbd.WIN_SERVICE.overlapped.hEvent), 0, 3000) if rc == win32event.WAIT_OBJECT_0: if mail: mail.send('stop') sabnzbd.save_state() logging.info('Leaving SABnzbd') sabnzbd.SABSTOP = True return else: time.sleep(3) # Check for loglevel changes if LOG_FLAG: LOG_FLAG = False level = LOGLEVELS[sabnzbd.cfg.log_level() + 1] logger.setLevel(level) if consoleLogging: console.setLevel(level) # 30 sec polling tasks if timer > 9: timer = 0 # Keep OS awake (if needed) sabnzbd.keep_awake() # Restart scheduler (if needed) scheduler.restart() # Save config (if needed) config.save_config() # Check the threads if not sabnzbd.check_all_tasks(): autorestarted = True sabnzbd.TRIGGER_RESTART = True # Notify guardian if sabnzbd.WIN_SERVICE and mail: mail.send('active') else: timer += 1 # 3 sec polling tasks # Check for auto-restart request # Or special restart cases like Mac and WindowsService if sabnzbd.TRIGGER_RESTART: # Shutdown cherrypy.engine.exit() sabnzbd.halt() sabnzbd.SABSTOP = True if sabnzbd.downloader.Downloader.do.paused: sabnzbd.RESTART_ARGS.append('-p') if autorestarted: sabnzbd.RESTART_ARGS.append('--autorestarted') sys.argv = sabnzbd.RESTART_ARGS os.chdir(org_dir) # If OSX frozen restart of app instead of embedded python if getattr(sys, 'frozen', None) == 'macosx_app': # [[NSProcessInfo processInfo] processIdentifier]] # logging.info("%s" % (NSProcessInfo.processInfo().processIdentifier())) my_pid = os.getpid() my_name = sabnzbd.MY_FULLNAME.replace('/Contents/MacOS/SABnzbd', '') my_args = ' '.join(sys.argv[1:]) cmd = 'kill -9 %s && open "%s" --args %s' % (my_pid, my_name, my_args) logging.info('Launching: ', cmd) os.system(cmd) elif sabnzbd.WIN_SERVICE and mail: logging.info('Asking the SABHelper service for a restart') mail.send('restart') mail.disconnect() return else: cherrypy.engine._do_execv() config.save_config() if sabnzbd.WINTRAY: sabnzbd.WINTRAY.terminate = True if sabnzbd.WIN_SERVICE and mail: mail.send('stop') if sabnzbd.WIN32: del_connection_info() if sabnzbd.FOUNDATION: sabnzbd.osxmenu.notify("SAB_Shutdown", None) logging.info('Leaving SABnzbd') sys.stderr.flush() sys.stdout.flush() sabnzbd.pid_file() if getattr(sys, 'frozen', None) == 'macosx_app': try: AppHelper.stopEventLoop() except: # Failing AppHelper libary! os._exit(0) else: notifier.send_notification('SABnzbd', T('SABnzbd shutdown finished'), 'startup') os._exit(0) ############################################################################## # Windows Service Support ############################################################################## if sabnzbd.WIN32: import servicemanager class SABnzbd(win32serviceutil.ServiceFramework): """ Win32 Service Handler """ _svc_name_ = 'SABnzbd' _svc_display_name_ = 'SABnzbd Binary Newsreader' _svc_deps_ = ["EventLog", "Tcpip", "SABHelper"] _svc_description_ = 'Automated downloading from Usenet. ' \ 'Set to "automatic" to start the service at system startup. ' \ 'You may need to login with a real user account when you need ' \ 'access to network shares.' def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.overlapped = pywintypes.OVERLAPPED() # @UndefinedVariable self.overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) sabnzbd.WIN_SERVICE = self def SvcDoRun(self): msg = 'SABnzbd-service %s' % sabnzbd.__version__ self.Logger(servicemanager.PYS_SERVICE_STARTED, msg + ' has started') sys.argv = get_serv_parms(self._svc_name_) main() self.Logger(servicemanager.PYS_SERVICE_STOPPED, msg + ' has stopped') def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) def Logger(self, state, msg): win32evtlogutil.ReportEvent(self._svc_display_name_, state, 0, servicemanager.EVENTLOG_INFORMATION_TYPE, (self._svc_name_, unicoder(msg))) def ErrLogger(self, msg, text): win32evtlogutil.ReportEvent(self._svc_display_name_, servicemanager.PYS_SERVICE_STOPPED, 0, servicemanager.EVENTLOG_ERROR_TYPE, (self._svc_name_, unicoder(msg)), unicoder(text)) def prep_service_parms(args): """ Prepare parameter list for service """ # Must store our original path, because the Python Service launcher # won't give it to us. serv = [os.path.normpath(os.path.abspath(sys.argv[0]))] # Convert the tuples to list for arg in args: serv.append(arg[0]) if arg[1]: serv.append(arg[1]) # Make sure we run in daemon mode serv.append('-d') return serv SERVICE_MSG = """ You may need to set additional Service parameters. Run services.msc from a command prompt. Don't forget to install the Service SABnzbd-helper.exe too! """ def HandleCommandLine(allow_service=True): """ Handle command line for a Windows Service Prescribed name that will be called by Py2Exe. You MUST set 'cmdline_style':'custom' in the package.py! Returns True when any service commands were detected. """ service, sab_opts, serv_opts, _upload_nzbs = commandline_handler() if service and not allow_service: # The other frozen apps don't support Services print "For service support, use SABnzbd-service.exe" return True elif service: if service in ('install', 'update'): # In this case check for required parameters path = get_f_option(sab_opts) if not path: print 'The -f parameter is required.\n' \ 'Use: -f %s' % service return True # First run the service installed, because this will # set the service key in the Registry win32serviceutil.HandleCommandLine(SABnzbd, argv=serv_opts) # Add our own parameter to the Registry sab_opts = prep_service_parms(sab_opts) if set_serv_parms(SABnzbd._svc_name_, sab_opts): print SERVICE_MSG else: print 'Cannot set required Registry info.' else: # Other service commands need no manipulation win32serviceutil.HandleCommandLine(SABnzbd) return bool(service) ############################################################################## # Platform specific startup code ############################################################################## if __name__ == '__main__': args = [] for txt in sys.argv: if ' ' in txt: txt = '"%s"' % unicoder(txt) else: txt = unicoder(txt) args.append(txt) sabnzbd.CMDLINE = ' '.join(args) if sabnzbd.WIN32: if not HandleCommandLine(allow_service=not hasattr(sys, "frozen")): main() elif getattr(sys, 'frozen', None) == 'macosx_app': try: # OSX binary runner from PyObjCTools import AppHelper from sabnzbd.osxmenu import SABnzbdDelegate class startApp(Thread): def __init__(self): logging.info('[osx] sabApp Starting - starting main thread') Thread.__init__(self) def run(self): main() logging.info('[osx] sabApp Stopping - main thread quit ') AppHelper.stopEventLoop() def stop(self): logging.info('[osx] sabApp Quit - stopping main thread ') sabnzbd.halt() cherrypy.engine.exit() sabnzbd.SABSTOP = True logging.info('[osx] sabApp Quit - main thread stopped') sabApp = startApp() sabApp.start() AppHelper.runEventLoop() except: main() else: main() SABnzbd-2.3.2/cherrypy/cherryd0000644000000000000000000000014513217004753014361 0ustar 00000000000000#! /usr/bin/env python import cherrypy.daemon if __name__ == '__main__': cherrypy.daemon.run() SABnzbd-2.3.2/cherrypy/daemon.py0000644000000000000000000000751113217005257014617 0ustar 00000000000000"""The CherryPy daemon.""" import sys import cherrypy from cherrypy.process import plugins, servers from cherrypy import Application def start(configfiles=None, daemonize=False, environment=None, fastcgi=False, scgi=False, pidfile=None, imports=None, cgi=False): """Subscribe all engine plugins and start the engine.""" sys.path = [''] + sys.path for i in imports or []: exec('import %s' % i) for c in configfiles or []: cherrypy.config.update(c) # If there's only one app mounted, merge config into it. if len(cherrypy.tree.apps) == 1: for app in cherrypy.tree.apps.values(): if isinstance(app, Application): app.merge(c) engine = cherrypy.engine if environment is not None: cherrypy.config.update({'environment': environment}) # Only daemonize if asked to. if daemonize: # Don't print anything to stdout/sterr. cherrypy.config.update({'log.screen': False}) plugins.Daemonizer(engine).subscribe() if pidfile: plugins.PIDFile(engine, pidfile).subscribe() if hasattr(engine, 'signal_handler'): engine.signal_handler.subscribe() if hasattr(engine, 'console_control_handler'): engine.console_control_handler.subscribe() if (fastcgi and (scgi or cgi)) or (scgi and cgi): cherrypy.log.error('You may only specify one of the cgi, fastcgi, and ' 'scgi options.', 'ENGINE') sys.exit(1) elif fastcgi or scgi or cgi: # Turn off autoreload when using *cgi. cherrypy.config.update({'engine.autoreload.on': False}) # Turn off the default HTTP server (which is subscribed by default). cherrypy.server.unsubscribe() addr = cherrypy.server.bind_addr cls = ( servers.FlupFCGIServer if fastcgi else servers.FlupSCGIServer if scgi else servers.FlupCGIServer ) f = cls(application=cherrypy.tree, bindAddress=addr) s = servers.ServerAdapter(engine, httpserver=f, bind_addr=addr) s.subscribe() # Always start the engine; this will start all other services try: engine.start() except: # Assume the error has been logged already via bus.log. sys.exit(1) else: engine.block() def run(): from optparse import OptionParser p = OptionParser() p.add_option('-c', '--config', action='append', dest='config', help='specify config file(s)') p.add_option('-d', action='store_true', dest='daemonize', help='run the server as a daemon') p.add_option('-e', '--environment', dest='environment', default=None, help='apply the given config environment') p.add_option('-f', action='store_true', dest='fastcgi', help='start a fastcgi server instead of the default HTTP ' 'server') p.add_option('-s', action='store_true', dest='scgi', help='start a scgi server instead of the default HTTP server') p.add_option('-x', action='store_true', dest='cgi', help='start a cgi server instead of the default HTTP server') p.add_option('-i', '--import', action='append', dest='imports', help='specify modules to import') p.add_option('-p', '--pidfile', dest='pidfile', default=None, help='store the process id in the given file') p.add_option('-P', '--Path', action='append', dest='Path', help='add the given paths to sys.path') options, args = p.parse_args() if options.Path: for p in options.Path: sys.path.insert(0, p) start(options.config, options.daemonize, options.environment, options.fastcgi, options.scgi, options.pidfile, options.imports, options.cgi) SABnzbd-2.3.2/cherrypy/favicon.ico0000644000000000000000000000257613217004753015131 0ustar 00000000000000h( HHm$5- pjVʼhc[XRMj|-&D=<|***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ '"   %#!      $ (  )  & "& &SABnzbd-2.3.2/cherrypy/VERSION.txt0000644000000000000000000000026113217005257014663 0ustar 00000000000000CherryPy 8.1.2 Official distribution: https://github.com/cherrypy/cherrypy/releases The folders 'tutorial', 'test' and 'scaffold' have been removed. This file has been added. SABnzbd-2.3.2/cherrypy/_cpchecker.py0000644000000000000000000003527213217005257015447 0ustar 00000000000000import os import warnings import cherrypy from cherrypy._cpcompat import iteritems, copykeys, builtins class Checker(object): """A checker for CherryPy sites and their mounted applications. When this object is called at engine startup, it executes each of its own methods whose names start with ``check_``. If you wish to disable selected checks, simply add a line in your global config which sets the appropriate method to False:: [global] checker.check_skipped_app_config = False You may also dynamically add or replace ``check_*`` methods in this way. """ on = True """If True (the default), run all checks; if False, turn off all checks.""" def __init__(self): self._populate_known_types() def __call__(self): """Run all check_* methods.""" if self.on: oldformatwarning = warnings.formatwarning warnings.formatwarning = self.formatwarning try: for name in dir(self): if name.startswith('check_'): method = getattr(self, name) if method and hasattr(method, '__call__'): method() finally: warnings.formatwarning = oldformatwarning def formatwarning(self, message, category, filename, lineno, line=None): """Function to format a warning.""" return 'CherryPy Checker:\n%s\n\n' % message # This value should be set inside _cpconfig. global_config_contained_paths = False def check_app_config_entries_dont_start_with_script_name(self): """Check for Application config with sections that repeat script_name. """ for sn, app in cherrypy.tree.apps.items(): if not isinstance(app, cherrypy.Application): continue if not app.config: continue if sn == '': continue sn_atoms = sn.strip('/').split('/') for key in app.config.keys(): key_atoms = key.strip('/').split('/') if key_atoms[:len(sn_atoms)] == sn_atoms: warnings.warn( 'The application mounted at %r has config ' 'entries that start with its script name: %r' % (sn, key)) def check_site_config_entries_in_app_config(self): """Check for mounted Applications that have site-scoped config.""" for sn, app in iteritems(cherrypy.tree.apps): if not isinstance(app, cherrypy.Application): continue msg = [] for section, entries in iteritems(app.config): if section.startswith('/'): for key, value in iteritems(entries): for n in ('engine.', 'server.', 'tree.', 'checker.'): if key.startswith(n): msg.append('[%s] %s = %s' % (section, key, value)) if msg: msg.insert(0, 'The application mounted at %r contains the ' 'following config entries, which are only allowed ' 'in site-wide config. Move them to a [global] ' 'section and pass them to cherrypy.config.update() ' 'instead of tree.mount().' % sn) warnings.warn(os.linesep.join(msg)) def check_skipped_app_config(self): """Check for mounted Applications that have no config.""" for sn, app in cherrypy.tree.apps.items(): if not isinstance(app, cherrypy.Application): continue if not app.config: msg = 'The Application mounted at %r has an empty config.' % sn if self.global_config_contained_paths: msg += (' It looks like the config you passed to ' 'cherrypy.config.update() contains application-' 'specific sections. You must explicitly pass ' 'application config via ' 'cherrypy.tree.mount(..., config=app_config)') warnings.warn(msg) return def check_app_config_brackets(self): """Check for Application config with extraneous brackets in section names. """ for sn, app in cherrypy.tree.apps.items(): if not isinstance(app, cherrypy.Application): continue if not app.config: continue for key in app.config.keys(): if key.startswith('[') or key.endswith(']'): warnings.warn( 'The application mounted at %r has config ' 'section names with extraneous brackets: %r. ' 'Config *files* need brackets; config *dicts* ' '(e.g. passed to tree.mount) do not.' % (sn, key)) def check_static_paths(self): """Check Application config for incorrect static paths.""" # Use the dummy Request object in the main thread. request = cherrypy.request for sn, app in cherrypy.tree.apps.items(): if not isinstance(app, cherrypy.Application): continue request.app = app for section in app.config: # get_resource will populate request.config request.get_resource(section + '/dummy.html') conf = request.config.get if conf('tools.staticdir.on', False): msg = '' root = conf('tools.staticdir.root') dir = conf('tools.staticdir.dir') if dir is None: msg = 'tools.staticdir.dir is not set.' else: fulldir = '' if os.path.isabs(dir): fulldir = dir if root: msg = ('dir is an absolute path, even ' 'though a root is provided.') testdir = os.path.join(root, dir[1:]) if os.path.exists(testdir): msg += ( '\nIf you meant to serve the ' 'filesystem folder at %r, remove the ' 'leading slash from dir.' % (testdir,)) else: if not root: msg = ( 'dir is a relative path and ' 'no root provided.') else: fulldir = os.path.join(root, dir) if not os.path.isabs(fulldir): msg = ('%r is not an absolute path.' % ( fulldir,)) if fulldir and not os.path.exists(fulldir): if msg: msg += '\n' msg += ('%r (root + dir) is not an existing ' 'filesystem path.' % fulldir) if msg: warnings.warn('%s\nsection: [%s]\nroot: %r\ndir: %r' % (msg, section, root, dir)) # -------------------------- Compatibility -------------------------- # obsolete = { 'server.default_content_type': 'tools.response_headers.headers', 'log_access_file': 'log.access_file', 'log_config_options': None, 'log_file': 'log.error_file', 'log_file_not_found': None, 'log_request_headers': 'tools.log_headers.on', 'log_to_screen': 'log.screen', 'show_tracebacks': 'request.show_tracebacks', 'throw_errors': 'request.throw_errors', 'profiler.on': ('cherrypy.tree.mount(profiler.make_app(' 'cherrypy.Application(Root())))'), } deprecated = {} def _compat(self, config): """Process config and warn on each obsolete or deprecated entry.""" for section, conf in config.items(): if isinstance(conf, dict): for k, v in conf.items(): if k in self.obsolete: warnings.warn('%r is obsolete. Use %r instead.\n' 'section: [%s]' % (k, self.obsolete[k], section)) elif k in self.deprecated: warnings.warn('%r is deprecated. Use %r instead.\n' 'section: [%s]' % (k, self.deprecated[k], section)) else: if section in self.obsolete: warnings.warn('%r is obsolete. Use %r instead.' % (section, self.obsolete[section])) elif section in self.deprecated: warnings.warn('%r is deprecated. Use %r instead.' % (section, self.deprecated[section])) def check_compatibility(self): """Process config and warn on each obsolete or deprecated entry.""" self._compat(cherrypy.config) for sn, app in cherrypy.tree.apps.items(): if not isinstance(app, cherrypy.Application): continue self._compat(app.config) # ------------------------ Known Namespaces ------------------------ # extra_config_namespaces = [] def _known_ns(self, app): ns = ['wsgi'] ns.extend(copykeys(app.toolboxes)) ns.extend(copykeys(app.namespaces)) ns.extend(copykeys(app.request_class.namespaces)) ns.extend(copykeys(cherrypy.config.namespaces)) ns += self.extra_config_namespaces for section, conf in app.config.items(): is_path_section = section.startswith('/') if is_path_section and isinstance(conf, dict): for k, v in conf.items(): atoms = k.split('.') if len(atoms) > 1: if atoms[0] not in ns: # Spit out a special warning if a known # namespace is preceded by "cherrypy." if atoms[0] == 'cherrypy' and atoms[1] in ns: msg = ( 'The config entry %r is invalid; ' 'try %r instead.\nsection: [%s]' % (k, '.'.join(atoms[1:]), section)) else: msg = ( 'The config entry %r is invalid, ' 'because the %r config namespace ' 'is unknown.\n' 'section: [%s]' % (k, atoms[0], section)) warnings.warn(msg) elif atoms[0] == 'tools': if atoms[1] not in dir(cherrypy.tools): msg = ( 'The config entry %r may be invalid, ' 'because the %r tool was not found.\n' 'section: [%s]' % (k, atoms[1], section)) warnings.warn(msg) def check_config_namespaces(self): """Process config and warn on each unknown config namespace.""" for sn, app in cherrypy.tree.apps.items(): if not isinstance(app, cherrypy.Application): continue self._known_ns(app) # -------------------------- Config Types -------------------------- # known_config_types = {} def _populate_known_types(self): b = [x for x in vars(builtins).values() if type(x) is type(str)] def traverse(obj, namespace): for name in dir(obj): # Hack for 3.2's warning about body_params if name == 'body_params': continue vtype = type(getattr(obj, name, None)) if vtype in b: self.known_config_types[namespace + '.' + name] = vtype traverse(cherrypy.request, 'request') traverse(cherrypy.response, 'response') traverse(cherrypy.server, 'server') traverse(cherrypy.engine, 'engine') traverse(cherrypy.log, 'log') def _known_types(self, config): msg = ('The config entry %r in section %r is of type %r, ' 'which does not match the expected type %r.') for section, conf in config.items(): if isinstance(conf, dict): for k, v in conf.items(): if v is not None: expected_type = self.known_config_types.get(k, None) vtype = type(v) if expected_type and vtype != expected_type: warnings.warn(msg % (k, section, vtype.__name__, expected_type.__name__)) else: k, v = section, conf if v is not None: expected_type = self.known_config_types.get(k, None) vtype = type(v) if expected_type and vtype != expected_type: warnings.warn(msg % (k, section, vtype.__name__, expected_type.__name__)) def check_config_types(self): """Assert that config values are of the same type as default values.""" self._known_types(cherrypy.config) for sn, app in cherrypy.tree.apps.items(): if not isinstance(app, cherrypy.Application): continue self._known_types(app.config) # -------------------- Specific config warnings -------------------- # def check_localhost(self): """Warn if any socket_host is 'localhost'. See #711.""" for k, v in cherrypy.config.items(): if k == 'server.socket_host' and v == 'localhost': warnings.warn("The use of 'localhost' as a socket host can " 'cause problems on newer systems, since ' "'localhost' can map to either an IPv4 or an " "IPv6 address. You should use '127.0.0.1' " "or '[::1]' instead.") SABnzbd-2.3.2/cherrypy/_cpcompat.py0000644000000000000000000002367713217005257015334 0ustar 00000000000000"""Compatibility code for using CherryPy with various versions of Python. CherryPy 3.2 is compatible with Python versions 2.6+. This module provides a useful abstraction over the differences between Python versions, sometimes by preferring a newer idiom, sometimes an older one, and sometimes a custom one. In particular, Python 2 uses str and '' for byte strings, while Python 3 uses str and '' for unicode strings. We will call each of these the 'native string' type for each version. Because of this major difference, this module provides two functions: 'ntob', which translates native strings (of type 'str') into byte strings regardless of Python version, and 'ntou', which translates native strings to unicode strings. This also provides a 'BytesIO' name for dealing specifically with bytes, and a 'StringIO' name for dealing with native strings. It also provides a 'base64_decode' function with native strings as input and output. """ import binascii import os import re import sys import threading import six if six.PY3: def ntob(n, encoding='ISO-8859-1'): """Return the given native string as a byte string in the given encoding. """ assert_native(n) # In Python 3, the native string type is unicode return n.encode(encoding) def ntou(n, encoding='ISO-8859-1'): """Return the given native string as a unicode string with the given encoding. """ assert_native(n) # In Python 3, the native string type is unicode return n def tonative(n, encoding='ISO-8859-1'): """Return the given string as a native string in the given encoding.""" # In Python 3, the native string type is unicode if isinstance(n, bytes): return n.decode(encoding) return n else: # Python 2 def ntob(n, encoding='ISO-8859-1'): """Return the given native string as a byte string in the given encoding. """ assert_native(n) # In Python 2, the native string type is bytes. Assume it's already # in the given encoding, which for ISO-8859-1 is almost always what # was intended. return n def ntou(n, encoding='ISO-8859-1'): """Return the given native string as a unicode string with the given encoding. """ assert_native(n) # In Python 2, the native string type is bytes. # First, check for the special encoding 'escape'. The test suite uses # this to signal that it wants to pass a string with embedded \uXXXX # escapes, but without having to prefix it with u'' for Python 2, # but no prefix for Python 3. if encoding == 'escape': return unicode( re.sub(r'\\u([0-9a-zA-Z]{4})', lambda m: unichr(int(m.group(1), 16)), n.decode('ISO-8859-1'))) # Assume it's already in the given encoding, which for ISO-8859-1 # is almost always what was intended. return n.decode(encoding) def tonative(n, encoding='ISO-8859-1'): """Return the given string as a native string in the given encoding.""" # In Python 2, the native string type is bytes. if isinstance(n, unicode): return n.encode(encoding) return n def assert_native(n): if not isinstance(n, str): raise TypeError('n must be a native str (got %s)' % type(n).__name__) try: # Python 3.1+ from base64 import decodebytes as _base64_decodebytes except ImportError: # Python 3.0- # since CherryPy claims compability with Python 2.3, we must use # the legacy API of base64 from base64 import decodestring as _base64_decodebytes def base64_decode(n, encoding='ISO-8859-1'): """Return the native string base64-decoded (as a native string).""" if isinstance(n, six.text_type): b = n.encode(encoding) else: b = n b = _base64_decodebytes(b) if str is six.text_type: return b.decode(encoding) else: return b try: sorted = sorted except NameError: def sorted(i): i = i[:] i.sort() return i try: reversed = reversed except NameError: def reversed(x): i = len(x) while i > 0: i -= 1 yield x[i] try: # Python 3 from urllib.parse import urljoin, urlencode from urllib.parse import quote, quote_plus from urllib.request import unquote, urlopen from urllib.request import parse_http_list, parse_keqv_list except ImportError: # Python 2 from urlparse import urljoin # noqa from urllib import urlencode, urlopen # noqa from urllib import quote, quote_plus # noqa from urllib import unquote # noqa from urllib2 import parse_http_list, parse_keqv_list # noqa try: dict.iteritems # Python 2 iteritems = lambda d: d.iteritems() copyitems = lambda d: d.items() except AttributeError: # Python 3 iteritems = lambda d: d.items() copyitems = lambda d: list(d.items()) try: dict.iterkeys # Python 2 iterkeys = lambda d: d.iterkeys() copykeys = lambda d: d.keys() except AttributeError: # Python 3 iterkeys = lambda d: d.keys() copykeys = lambda d: list(d.keys()) try: dict.itervalues # Python 2 itervalues = lambda d: d.itervalues() copyvalues = lambda d: d.values() except AttributeError: # Python 3 itervalues = lambda d: d.values() copyvalues = lambda d: list(d.values()) try: # Python 3 import builtins except ImportError: # Python 2 import __builtin__ as builtins # noqa try: # Python 2. We try Python 2 first clients on Python 2 # don't try to import the 'http' module from cherrypy.lib from Cookie import SimpleCookie, CookieError from httplib import BadStatusLine, HTTPConnection, IncompleteRead from httplib import NotConnected from BaseHTTPServer import BaseHTTPRequestHandler except ImportError: # Python 3 from http.cookies import SimpleCookie, CookieError # noqa from http.client import BadStatusLine, HTTPConnection, IncompleteRead # noqa from http.client import NotConnected # noqa from http.server import BaseHTTPRequestHandler # noqa # Some platforms don't expose HTTPSConnection, so handle it separately if six.PY3: try: from http.client import HTTPSConnection except ImportError: # Some platforms which don't have SSL don't expose HTTPSConnection HTTPSConnection = None else: try: from httplib import HTTPSConnection except ImportError: HTTPSConnection = None try: # Python 2 xrange = xrange except NameError: # Python 3 xrange = range try: # Python 3 from urllib.parse import unquote as parse_unquote def unquote_qs(atom, encoding, errors='strict'): return parse_unquote( atom.replace('+', ' '), encoding=encoding, errors=errors) except ImportError: # Python 2 from urllib import unquote as parse_unquote def unquote_qs(atom, encoding, errors='strict'): return parse_unquote(atom.replace('+', ' ')).decode(encoding, errors) try: # Prefer simplejson, which is usually more advanced than the builtin # module. import simplejson as json json_decode = json.JSONDecoder().decode _json_encode = json.JSONEncoder().iterencode except ImportError: if sys.version_info >= (2, 6): # Python >=2.6 : json is part of the standard library import json json_decode = json.JSONDecoder().decode _json_encode = json.JSONEncoder().iterencode else: json = None def json_decode(s): raise ValueError('No JSON library is available') def _json_encode(s): raise ValueError('No JSON library is available') finally: if json and six.PY3: # The two Python 3 implementations (simplejson/json) # outputs str. We need bytes. def json_encode(value): for chunk in _json_encode(value): yield chunk.encode('utf8') else: json_encode = _json_encode text_or_bytes = six.text_type, six.binary_type try: import cPickle as pickle except ImportError: # In Python 2, pickle is a Python version. # In Python 3, pickle is the sped-up C version. import pickle # noqa def random20(): return binascii.hexlify(os.urandom(20)).decode('ascii') try: from _thread import get_ident as get_thread_ident except ImportError: from thread import get_ident as get_thread_ident # noqa try: # Python 3 next = next except NameError: # Python 2 def next(i): return i.next() if sys.version_info >= (3, 3): Timer = threading.Timer Event = threading.Event else: # Python 3.2 and earlier Timer = threading._Timer Event = threading._Event try: # Python 2.7+ from subprocess import _args_from_interpreter_flags except ImportError: def _args_from_interpreter_flags(): """Tries to reconstruct original interpreter args from sys.flags for Python 2.6 Backported from Python 3.5. Aims to return a list of command-line arguments reproducing the current settings in sys.flags and sys.warnoptions. """ flag_opt_map = { 'debug': 'd', # 'inspect': 'i', # 'interactive': 'i', 'optimize': 'O', 'dont_write_bytecode': 'B', 'no_user_site': 's', 'no_site': 'S', 'ignore_environment': 'E', 'verbose': 'v', 'bytes_warning': 'b', 'quiet': 'q', 'hash_randomization': 'R', 'py3k_warning': '3', } args = [] for flag, opt in flag_opt_map.items(): v = getattr(sys.flags, flag) if v > 0: if flag == 'hash_randomization': v = 1 # Handle specification of an exact seed args.append('-' + opt * v) for opt in sys.warnoptions: args.append('-W' + opt) return args SABnzbd-2.3.2/cherrypy/_cpconfig.py0000644000000000000000000002350013217005257015277 0ustar 00000000000000""" Configuration system for CherryPy. Configuration in CherryPy is implemented via dictionaries. Keys are strings which name the mapped value, which may be of any type. Architecture ------------ CherryPy Requests are part of an Application, which runs in a global context, and configuration data may apply to any of those three scopes: Global Configuration entries which apply everywhere are stored in cherrypy.config. Application Entries which apply to each mounted application are stored on the Application object itself, as 'app.config'. This is a two-level dict where each key is a path, or "relative URL" (for example, "/" or "/path/to/my/page"), and each value is a config dict. Usually, this data is provided in the call to tree.mount(root(), config=conf), although you may also use app.merge(conf). Request Each Request object possesses a single 'Request.config' dict. Early in the request process, this dict is populated by merging global config entries, Application entries (whose path equals or is a parent of Request.path_info), and any config acquired while looking up the page handler (see next). Declaration ----------- Configuration data may be supplied as a Python dictionary, as a filename, or as an open file object. When you supply a filename or file, CherryPy uses Python's builtin ConfigParser; you declare Application config by writing each path as a section header:: [/path/to/my/page] request.stream = True To declare global configuration entries, place them in a [global] section. You may also declare config entries directly on the classes and methods (page handlers) that make up your CherryPy application via the ``_cp_config`` attribute, set with the ``cherrypy.config`` decorator. For example:: @cherrypy.config(**{'tools.gzip.on': True}) class Demo: @cherrypy.expose @cherrypy.config(**{'request.show_tracebacks': False}) def index(self): return "Hello world" .. note:: This behavior is only guaranteed for the default dispatcher. Other dispatchers may have different restrictions on where you can attach config attributes. Namespaces ---------- Configuration keys are separated into namespaces by the first "." in the key. Current namespaces: engine Controls the 'application engine', including autoreload. These can only be declared in the global config. tree Grafts cherrypy.Application objects onto cherrypy.tree. These can only be declared in the global config. hooks Declares additional request-processing functions. log Configures the logging for each application. These can only be declared in the global or / config. request Adds attributes to each Request. response Adds attributes to each Response. server Controls the default HTTP server via cherrypy.server. These can only be declared in the global config. tools Runs and configures additional request-processing packages. wsgi Adds WSGI middleware to an Application's "pipeline". These can only be declared in the app's root config ("/"). checker Controls the 'checker', which looks for common errors in app state (including config) when the engine starts. Global config only. The only key that does not exist in a namespace is the "environment" entry. This special entry 'imports' other config entries from a template stored in cherrypy._cpconfig.environments[environment]. It only applies to the global config, and only when you use cherrypy.config.update. You can define your own namespaces to be called at the Global, Application, or Request level, by adding a named handler to cherrypy.config.namespaces, app.namespaces, or app.request_class.namespaces. The name can be any string, and the handler must be either a callable or a (Python 2.5 style) context manager. """ import cherrypy from cherrypy._cpcompat import text_or_bytes from cherrypy.lib import reprconf # Deprecated in CherryPy 3.2--remove in 3.3 NamespaceSet = reprconf.NamespaceSet def merge(base, other): """Merge one app config (from a dict, file, or filename) into another. If the given config is a filename, it will be appended to the list of files to monitor for "autoreload" changes. """ if isinstance(other, text_or_bytes): cherrypy.engine.autoreload.files.add(other) # Load other into base for section, value_map in reprconf.as_dict(other).items(): if not isinstance(value_map, dict): raise ValueError( 'Application config must include section headers, but the ' "config you tried to merge doesn't have any sections. " 'Wrap your config in another dict with paths as section ' "headers, for example: {'/': config}.") base.setdefault(section, {}).update(value_map) class Config(reprconf.Config): """The 'global' configuration data for the entire CherryPy process.""" def update(self, config): """Update self from a dict, file or filename.""" if isinstance(config, text_or_bytes): # Filename cherrypy.engine.autoreload.files.add(config) reprconf.Config.update(self, config) def _apply(self, config): """Update self from a dict.""" if isinstance(config.get('global'), dict): if len(config) > 1: cherrypy.checker.global_config_contained_paths = True config = config['global'] if 'tools.staticdir.dir' in config: config['tools.staticdir.section'] = 'global' reprconf.Config._apply(self, config) @staticmethod def __call__(*args, **kwargs): """Decorator for page handlers to set _cp_config.""" if args: raise TypeError( 'The cherrypy.config decorator does not accept positional ' 'arguments; you must use keyword arguments.') def tool_decorator(f): _Vars(f).setdefault('_cp_config', {}).update(kwargs) return f return tool_decorator class _Vars(object): """ Adapter that allows setting a default attribute on a function or class. """ def __init__(self, target): self.target = target def setdefault(self, key, default): if not hasattr(self.target, key): setattr(self.target, key, default) return getattr(self.target, key) # Sphinx begin config.environments Config.environments = environments = { 'staging': { 'engine.autoreload.on': False, 'checker.on': False, 'tools.log_headers.on': False, 'request.show_tracebacks': False, 'request.show_mismatched_params': False, }, 'production': { 'engine.autoreload.on': False, 'checker.on': False, 'tools.log_headers.on': False, 'request.show_tracebacks': False, 'request.show_mismatched_params': False, 'log.screen': False, }, 'embedded': { # For use with CherryPy embedded in another deployment stack. 'engine.autoreload.on': False, 'checker.on': False, 'tools.log_headers.on': False, 'request.show_tracebacks': False, 'request.show_mismatched_params': False, 'log.screen': False, 'engine.SIGHUP': None, 'engine.SIGTERM': None, }, 'test_suite': { 'engine.autoreload.on': False, 'checker.on': False, 'tools.log_headers.on': False, 'request.show_tracebacks': True, 'request.show_mismatched_params': True, 'log.screen': False, }, } # Sphinx end config.environments def _server_namespace_handler(k, v): """Config handler for the "server" namespace.""" atoms = k.split('.', 1) if len(atoms) > 1: # Special-case config keys of the form 'server.servername.socket_port' # to configure additional HTTP servers. if not hasattr(cherrypy, 'servers'): cherrypy.servers = {} servername, k = atoms if servername not in cherrypy.servers: from cherrypy import _cpserver cherrypy.servers[servername] = _cpserver.Server() # On by default, but 'on = False' can unsubscribe it (see below). cherrypy.servers[servername].subscribe() if k == 'on': if v: cherrypy.servers[servername].subscribe() else: cherrypy.servers[servername].unsubscribe() else: setattr(cherrypy.servers[servername], k, v) else: setattr(cherrypy.server, k, v) Config.namespaces['server'] = _server_namespace_handler def _engine_namespace_handler(k, v): """Config handler for the "engine" namespace.""" engine = cherrypy.engine if k == 'SIGHUP': engine.subscribe('SIGHUP', v) elif k == 'SIGTERM': engine.subscribe('SIGTERM', v) elif '.' in k: plugin, attrname = k.split('.', 1) plugin = getattr(engine, plugin) if attrname == 'on': if v and hasattr(getattr(plugin, 'subscribe', None), '__call__'): plugin.subscribe() return elif ( (not v) and hasattr(getattr(plugin, 'unsubscribe', None), '__call__') ): plugin.unsubscribe() return setattr(plugin, attrname, v) else: setattr(engine, k, v) Config.namespaces['engine'] = _engine_namespace_handler def _tree_namespace_handler(k, v): """Namespace handler for the 'tree' config namespace.""" if isinstance(v, dict): for script_name, app in v.items(): cherrypy.tree.graft(app, script_name) msg = 'Mounted: %s on %s' % (app, script_name or '/') cherrypy.engine.log(msg) else: cherrypy.tree.graft(v, v.script_name) cherrypy.engine.log('Mounted: %s on %s' % (v, v.script_name or '/')) Config.namespaces['tree'] = _tree_namespace_handler SABnzbd-2.3.2/cherrypy/_cpdispatch.py0000644000000000000000000006132713217005257015642 0ustar 00000000000000"""CherryPy dispatchers. A 'dispatcher' is the object which looks up the 'page handler' callable and collects config for the current request based on the path_info, other request attributes, and the application architecture. The core calls the dispatcher as early as possible, passing it a 'path_info' argument. The default dispatcher discovers the page handler by matching path_info to a hierarchical arrangement of objects, starting at request.app.root. """ import string import sys import types try: classtype = (type, types.ClassType) except AttributeError: classtype = type import cherrypy class PageHandler(object): """Callable which sets response.body.""" def __init__(self, callable, *args, **kwargs): self.callable = callable self.args = args self.kwargs = kwargs def get_args(self): return cherrypy.serving.request.args def set_args(self, args): cherrypy.serving.request.args = args return cherrypy.serving.request.args args = property( get_args, set_args, doc='The ordered args should be accessible from post dispatch hooks' ) def get_kwargs(self): return cherrypy.serving.request.kwargs def set_kwargs(self, kwargs): cherrypy.serving.request.kwargs = kwargs return cherrypy.serving.request.kwargs kwargs = property( get_kwargs, set_kwargs, doc='The named kwargs should be accessible from post dispatch hooks' ) def __call__(self): try: return self.callable(*self.args, **self.kwargs) except TypeError: x = sys.exc_info()[1] try: test_callable_spec(self.callable, self.args, self.kwargs) except cherrypy.HTTPError: raise sys.exc_info()[1] except: raise x raise def test_callable_spec(callable, callable_args, callable_kwargs): """ Inspect callable and test to see if the given args are suitable for it. When an error occurs during the handler's invoking stage there are 2 erroneous cases: 1. Too many parameters passed to a function which doesn't define one of *args or **kwargs. 2. Too little parameters are passed to the function. There are 3 sources of parameters to a cherrypy handler. 1. query string parameters are passed as keyword parameters to the handler. 2. body parameters are also passed as keyword parameters. 3. when partial matching occurs, the final path atoms are passed as positional args. Both the query string and path atoms are part of the URI. If they are incorrect, then a 404 Not Found should be raised. Conversely the body parameters are part of the request; if they are invalid a 400 Bad Request. """ show_mismatched_params = getattr( cherrypy.serving.request, 'show_mismatched_params', False) try: (args, varargs, varkw, defaults) = getargspec(callable) except TypeError: if isinstance(callable, object) and hasattr(callable, '__call__'): (args, varargs, varkw, defaults) = getargspec(callable.__call__) else: # If it wasn't one of our own types, re-raise # the original error raise if args and args[0] == 'self': args = args[1:] arg_usage = dict([(arg, 0,) for arg in args]) vararg_usage = 0 varkw_usage = 0 extra_kwargs = set() for i, value in enumerate(callable_args): try: arg_usage[args[i]] += 1 except IndexError: vararg_usage += 1 for key in callable_kwargs.keys(): try: arg_usage[key] += 1 except KeyError: varkw_usage += 1 extra_kwargs.add(key) # figure out which args have defaults. args_with_defaults = args[-len(defaults or []):] for i, val in enumerate(defaults or []): # Defaults take effect only when the arg hasn't been used yet. if arg_usage[args_with_defaults[i]] == 0: arg_usage[args_with_defaults[i]] += 1 missing_args = [] multiple_args = [] for key, usage in arg_usage.items(): if usage == 0: missing_args.append(key) elif usage > 1: multiple_args.append(key) if missing_args: # In the case where the method allows body arguments # there are 3 potential errors: # 1. not enough query string parameters -> 404 # 2. not enough body parameters -> 400 # 3. not enough path parts (partial matches) -> 404 # # We can't actually tell which case it is, # so I'm raising a 404 because that covers 2/3 of the # possibilities # # In the case where the method does not allow body # arguments it's definitely a 404. message = None if show_mismatched_params: message = 'Missing parameters: %s' % ','.join(missing_args) raise cherrypy.HTTPError(404, message=message) # the extra positional arguments come from the path - 404 Not Found if not varargs and vararg_usage > 0: raise cherrypy.HTTPError(404) body_params = cherrypy.serving.request.body.params or {} body_params = set(body_params.keys()) qs_params = set(callable_kwargs.keys()) - body_params if multiple_args: if qs_params.intersection(set(multiple_args)): # If any of the multiple parameters came from the query string then # it's a 404 Not Found error = 404 else: # Otherwise it's a 400 Bad Request error = 400 message = None if show_mismatched_params: message = 'Multiple values for parameters: '\ '%s' % ','.join(multiple_args) raise cherrypy.HTTPError(error, message=message) if not varkw and varkw_usage > 0: # If there were extra query string parameters, it's a 404 Not Found extra_qs_params = set(qs_params).intersection(extra_kwargs) if extra_qs_params: message = None if show_mismatched_params: message = 'Unexpected query string '\ 'parameters: %s' % ', '.join(extra_qs_params) raise cherrypy.HTTPError(404, message=message) # If there were any extra body parameters, it's a 400 Not Found extra_body_params = set(body_params).intersection(extra_kwargs) if extra_body_params: message = None if show_mismatched_params: message = 'Unexpected body parameters: '\ '%s' % ', '.join(extra_body_params) raise cherrypy.HTTPError(400, message=message) try: import inspect except ImportError: test_callable_spec = lambda callable, args, kwargs: None else: getargspec = inspect.getargspec # Python 3 requires using getfullargspec if keyword-only arguments are present if hasattr(inspect, 'getfullargspec'): def getargspec(callable): return inspect.getfullargspec(callable)[:4] class LateParamPageHandler(PageHandler): """When passing cherrypy.request.params to the page handler, we do not want to capture that dict too early; we want to give tools like the decoding tool a chance to modify the params dict in-between the lookup of the handler and the actual calling of the handler. This subclass takes that into account, and allows request.params to be 'bound late' (it's more complicated than that, but that's the effect). """ def _get_kwargs(self): kwargs = cherrypy.serving.request.params.copy() if self._kwargs: kwargs.update(self._kwargs) return kwargs def _set_kwargs(self, kwargs): cherrypy.serving.request.kwargs = kwargs self._kwargs = kwargs kwargs = property(_get_kwargs, _set_kwargs, doc='page handler kwargs (with ' 'cherrypy.request.params copied in)') if sys.version_info < (3, 0): punctuation_to_underscores = string.maketrans( string.punctuation, '_' * len(string.punctuation)) def validate_translator(t): if not isinstance(t, str) or len(t) != 256: raise ValueError( 'The translate argument must be a str of len 256.') else: punctuation_to_underscores = str.maketrans( string.punctuation, '_' * len(string.punctuation)) def validate_translator(t): if not isinstance(t, dict): raise ValueError('The translate argument must be a dict.') class Dispatcher(object): """CherryPy Dispatcher which walks a tree of objects to find a handler. The tree is rooted at cherrypy.request.app.root, and each hierarchical component in the path_info argument is matched to a corresponding nested attribute of the root object. Matching handlers must have an 'exposed' attribute which evaluates to True. The special method name "index" matches a URI which ends in a slash ("/"). The special method name "default" may match a portion of the path_info (but only when no longer substring of the path_info matches some other object). This is the default, built-in dispatcher for CherryPy. """ dispatch_method_name = '_cp_dispatch' """ The name of the dispatch method that nodes may optionally implement to provide their own dynamic dispatch algorithm. """ def __init__(self, dispatch_method_name=None, translate=punctuation_to_underscores): validate_translator(translate) self.translate = translate if dispatch_method_name: self.dispatch_method_name = dispatch_method_name def __call__(self, path_info): """Set handler and config for the current request.""" request = cherrypy.serving.request func, vpath = self.find_handler(path_info) if func: # Decode any leftover %2F in the virtual_path atoms. vpath = [x.replace('%2F', '/') for x in vpath] request.handler = LateParamPageHandler(func, *vpath) else: request.handler = cherrypy.NotFound() def find_handler(self, path): """Return the appropriate page handler, plus any virtual path. This will return two objects. The first will be a callable, which can be used to generate page output. Any parameters from the query string or request body will be sent to that callable as keyword arguments. The callable is found by traversing the application's tree, starting from cherrypy.request.app.root, and matching path components to successive objects in the tree. For example, the URL "/path/to/handler" might return root.path.to.handler. The second object returned will be a list of names which are 'virtual path' components: parts of the URL which are dynamic, and were not used when looking up the handler. These virtual path components are passed to the handler as positional arguments. """ request = cherrypy.serving.request app = request.app root = app.root dispatch_name = self.dispatch_method_name # Get config for the root object/path. fullpath = [x for x in path.strip('/').split('/') if x] + ['index'] fullpath_len = len(fullpath) segleft = fullpath_len nodeconf = {} if hasattr(root, '_cp_config'): nodeconf.update(root._cp_config) if '/' in app.config: nodeconf.update(app.config['/']) object_trail = [['root', root, nodeconf, segleft]] node = root iternames = fullpath[:] while iternames: name = iternames[0] # map to legal Python identifiers (e.g. replace '.' with '_') objname = name.translate(self.translate) nodeconf = {} subnode = getattr(node, objname, None) pre_len = len(iternames) if subnode is None: dispatch = getattr(node, dispatch_name, None) if dispatch and hasattr(dispatch, '__call__') and not \ getattr(dispatch, 'exposed', False) and \ pre_len > 1: # Don't expose the hidden 'index' token to _cp_dispatch # We skip this if pre_len == 1 since it makes no sense # to call a dispatcher when we have no tokens left. index_name = iternames.pop() subnode = dispatch(vpath=iternames) iternames.append(index_name) else: # We didn't find a path, but keep processing in case there # is a default() handler. iternames.pop(0) else: # We found the path, remove the vpath entry iternames.pop(0) segleft = len(iternames) if segleft > pre_len: # No path segment was removed. Raise an error. raise cherrypy.CherryPyException( 'A vpath segment was added. Custom dispatchers may only ' + 'remove elements. While trying to process ' + '{0} in {1}'.format(name, fullpath) ) elif segleft == pre_len: # Assume that the handler used the current path segment, but # did not pop it. This allows things like # return getattr(self, vpath[0], None) iternames.pop(0) segleft -= 1 node = subnode if node is not None: # Get _cp_config attached to this node. if hasattr(node, '_cp_config'): nodeconf.update(node._cp_config) # Mix in values from app.config for this path. existing_len = fullpath_len - pre_len if existing_len != 0: curpath = '/' + '/'.join(fullpath[0:existing_len]) else: curpath = '' new_segs = fullpath[fullpath_len - pre_len:fullpath_len - segleft] for seg in new_segs: curpath += '/' + seg if curpath in app.config: nodeconf.update(app.config[curpath]) object_trail.append([name, node, nodeconf, segleft]) def set_conf(): """Collapse all object_trail config into cherrypy.request.config. """ base = cherrypy.config.copy() # Note that we merge the config from each node # even if that node was None. for name, obj, conf, segleft in object_trail: base.update(conf) if 'tools.staticdir.dir' in conf: base['tools.staticdir.section'] = '/' + \ '/'.join(fullpath[0:fullpath_len - segleft]) return base # Try successive objects (reverse order) num_candidates = len(object_trail) - 1 for i in range(num_candidates, -1, -1): name, candidate, nodeconf, segleft = object_trail[i] if candidate is None: continue # Try a "default" method on the current leaf. if hasattr(candidate, 'default'): defhandler = candidate.default if getattr(defhandler, 'exposed', False): # Insert any extra _cp_config from the default handler. conf = getattr(defhandler, '_cp_config', {}) object_trail.insert( i + 1, ['default', defhandler, conf, segleft]) request.config = set_conf() # See https://github.com/cherrypy/cherrypy/issues/613 request.is_index = path.endswith('/') return defhandler, fullpath[fullpath_len - segleft:-1] # Uncomment the next line to restrict positional params to # "default". # if i < num_candidates - 2: continue # Try the current leaf. if getattr(candidate, 'exposed', False): request.config = set_conf() if i == num_candidates: # We found the extra ".index". Mark request so tools # can redirect if path_info has no trailing slash. request.is_index = True else: # We're not at an 'index' handler. Mark request so tools # can redirect if path_info has NO trailing slash. # Note that this also includes handlers which take # positional parameters (virtual paths). request.is_index = False return candidate, fullpath[fullpath_len - segleft:-1] # We didn't find anything request.config = set_conf() return None, [] class MethodDispatcher(Dispatcher): """Additional dispatch based on cherrypy.request.method.upper(). Methods named GET, POST, etc will be called on an exposed class. The method names must be all caps; the appropriate Allow header will be output showing all capitalized method names as allowable HTTP verbs. Note that the containing class must be exposed, not the methods. """ def __call__(self, path_info): """Set handler and config for the current request.""" request = cherrypy.serving.request resource, vpath = self.find_handler(path_info) if resource: # Set Allow header avail = [m for m in dir(resource) if m.isupper()] if 'GET' in avail and 'HEAD' not in avail: avail.append('HEAD') avail.sort() cherrypy.serving.response.headers['Allow'] = ', '.join(avail) # Find the subhandler meth = request.method.upper() func = getattr(resource, meth, None) if func is None and meth == 'HEAD': func = getattr(resource, 'GET', None) if func: # Grab any _cp_config on the subhandler. if hasattr(func, '_cp_config'): request.config.update(func._cp_config) # Decode any leftover %2F in the virtual_path atoms. vpath = [x.replace('%2F', '/') for x in vpath] request.handler = LateParamPageHandler(func, *vpath) else: request.handler = cherrypy.HTTPError(405) else: request.handler = cherrypy.NotFound() class RoutesDispatcher(object): """A Routes based dispatcher for CherryPy.""" def __init__(self, full_result=False, **mapper_options): """ Routes dispatcher Set full_result to True if you wish the controller and the action to be passed on to the page handler parameters. By default they won't be. """ import routes self.full_result = full_result self.controllers = {} self.mapper = routes.Mapper(**mapper_options) self.mapper.controller_scan = self.controllers.keys def connect(self, name, route, controller, **kwargs): self.controllers[name] = controller self.mapper.connect(name, route, controller=name, **kwargs) def redirect(self, url): raise cherrypy.HTTPRedirect(url) def __call__(self, path_info): """Set handler and config for the current request.""" func = self.find_handler(path_info) if func: cherrypy.serving.request.handler = LateParamPageHandler(func) else: cherrypy.serving.request.handler = cherrypy.NotFound() def find_handler(self, path_info): """Find the right page handler, and set request.config.""" import routes request = cherrypy.serving.request config = routes.request_config() config.mapper = self.mapper if hasattr(request, 'wsgi_environ'): config.environ = request.wsgi_environ config.host = request.headers.get('Host', None) config.protocol = request.scheme config.redirect = self.redirect result = self.mapper.match(path_info) config.mapper_dict = result params = {} if result: params = result.copy() if not self.full_result: params.pop('controller', None) params.pop('action', None) request.params.update(params) # Get config for the root object/path. request.config = base = cherrypy.config.copy() curpath = '' def merge(nodeconf): if 'tools.staticdir.dir' in nodeconf: nodeconf['tools.staticdir.section'] = curpath or '/' base.update(nodeconf) app = request.app root = app.root if hasattr(root, '_cp_config'): merge(root._cp_config) if '/' in app.config: merge(app.config['/']) # Mix in values from app.config. atoms = [x for x in path_info.split('/') if x] if atoms: last = atoms.pop() else: last = None for atom in atoms: curpath = '/'.join((curpath, atom)) if curpath in app.config: merge(app.config[curpath]) handler = None if result: controller = result.get('controller') controller = self.controllers.get(controller, controller) if controller: if isinstance(controller, classtype): controller = controller() # Get config from the controller. if hasattr(controller, '_cp_config'): merge(controller._cp_config) action = result.get('action') if action is not None: handler = getattr(controller, action, None) # Get config from the handler if hasattr(handler, '_cp_config'): merge(handler._cp_config) else: handler = controller # Do the last path atom here so it can # override the controller's _cp_config. if last: curpath = '/'.join((curpath, last)) if curpath in app.config: merge(app.config[curpath]) return handler def XMLRPCDispatcher(next_dispatcher=Dispatcher()): from cherrypy.lib import xmlrpcutil def xmlrpc_dispatch(path_info): path_info = xmlrpcutil.patched_path(path_info) return next_dispatcher(path_info) return xmlrpc_dispatch def VirtualHost(next_dispatcher=Dispatcher(), use_x_forwarded_host=True, **domains): """ Select a different handler based on the Host header. This can be useful when running multiple sites within one CP server. It allows several domains to point to different parts of a single website structure. For example:: http://www.domain.example -> root http://www.domain2.example -> root/domain2/ http://www.domain2.example:443 -> root/secure can be accomplished via the following config:: [/] request.dispatch = cherrypy.dispatch.VirtualHost( **{'www.domain2.example': '/domain2', 'www.domain2.example:443': '/secure', }) next_dispatcher The next dispatcher object in the dispatch chain. The VirtualHost dispatcher adds a prefix to the URL and calls another dispatcher. Defaults to cherrypy.dispatch.Dispatcher(). use_x_forwarded_host If True (the default), any "X-Forwarded-Host" request header will be used instead of the "Host" header. This is commonly added by HTTP servers (such as Apache) when proxying. ``**domains`` A dict of {host header value: virtual prefix} pairs. The incoming "Host" request header is looked up in this dict, and, if a match is found, the corresponding "virtual prefix" value will be prepended to the URL path before calling the next dispatcher. Note that you often need separate entries for "example.com" and "www.example.com". In addition, "Host" headers may contain the port number. """ from cherrypy.lib import httputil def vhost_dispatch(path_info): request = cherrypy.serving.request header = request.headers.get domain = header('Host', '') if use_x_forwarded_host: domain = header('X-Forwarded-Host', domain) prefix = domains.get(domain, '') if prefix: path_info = httputil.urljoin(prefix, path_info) result = next_dispatcher(path_info) # Touch up staticdir config. See # https://github.com/cherrypy/cherrypy/issues/614. section = request.config.get('tools.staticdir.section') if section: section = section[len(prefix):] request.config['tools.staticdir.section'] = section return result return vhost_dispatch SABnzbd-2.3.2/cherrypy/_cperror.py0000644000000000000000000005372713217005257015201 0ustar 00000000000000"""Exception classes for CherryPy. CherryPy provides (and uses) exceptions for declaring that the HTTP response should be a status other than the default "200 OK". You can ``raise`` them like normal Python exceptions. You can also call them and they will raise themselves; this means you can set an :class:`HTTPError` or :class:`HTTPRedirect` as the :attr:`request.handler`. .. _redirectingpost: Redirecting POST ================ When you GET a resource and are redirected by the server to another Location, there's generally no problem since GET is both a "safe method" (there should be no side-effects) and an "idempotent method" (multiple calls are no different than a single call). POST, however, is neither safe nor idempotent--if you charge a credit card, you don't want to be charged twice by a redirect! For this reason, *none* of the 3xx responses permit a user-agent (browser) to resubmit a POST on redirection without first confirming the action with the user: ===== ================================= =========== 300 Multiple Choices Confirm with the user 301 Moved Permanently Confirm with the user 302 Found (Object moved temporarily) Confirm with the user 303 See Other GET the new URI--no confirmation 304 Not modified (for conditional GET only--POST should not raise this error) 305 Use Proxy Confirm with the user 307 Temporary Redirect Confirm with the user ===== ================================= =========== However, browsers have historically implemented these restrictions poorly; in particular, many browsers do not force the user to confirm 301, 302 or 307 when redirecting POST. For this reason, CherryPy defaults to 303, which most user-agents appear to have implemented correctly. Therefore, if you raise HTTPRedirect for a POST request, the user-agent will most likely attempt to GET the new URI (without asking for confirmation from the user). We realize this is confusing for developers, but it's the safest thing we could do. You are of course free to raise ``HTTPRedirect(uri, status=302)`` or any other 3xx status if you know what you're doing, but given the environment, we couldn't let any of those be the default. Custom Error Handling ===================== .. image:: /refman/cperrors.gif Anticipated HTTP responses -------------------------- The 'error_page' config namespace can be used to provide custom HTML output for expected responses (like 404 Not Found). Supply a filename from which the output will be read. The contents will be interpolated with the values %(status)s, %(message)s, %(traceback)s, and %(version)s using plain old Python `string formatting `_. :: _cp_config = { 'error_page.404': os.path.join(localDir, "static/index.html") } Beginning in version 3.1, you may also provide a function or other callable as an error_page entry. It will be passed the same status, message, traceback and version arguments that are interpolated into templates:: def error_page_402(status, message, traceback, version): return "Error %s - Well, I'm very sorry but you haven't paid!" % status cherrypy.config.update({'error_page.402': error_page_402}) Also in 3.1, in addition to the numbered error codes, you may also supply "error_page.default" to handle all codes which do not have their own error_page entry. Unanticipated errors -------------------- CherryPy also has a generic error handling mechanism: whenever an unanticipated error occurs in your code, it will call :func:`Request.error_response` to set the response status, headers, and body. By default, this is the same output as :class:`HTTPError(500) `. If you want to provide some other behavior, you generally replace "request.error_response". Here is some sample code that shows how to display a custom error message and send an e-mail containing the error:: from cherrypy import _cperror def handle_error(): cherrypy.response.status = 500 cherrypy.response.body = [ "Sorry, an error occured" ] sendMail('error@domain.com', 'Error in your web app', _cperror.format_exc()) @cherrypy.config(**{'request.error_response': handle_error}) class Root: pass Note that you have to explicitly set :attr:`response.body ` and not simply return an error message as a result. """ import contextlib from cgi import escape as _escape from sys import exc_info as _exc_info from traceback import format_exception as _format_exception from xml.sax import saxutils import six from cherrypy._cpcompat import text_or_bytes, iteritems, ntob from cherrypy._cpcompat import tonative, urljoin as _urljoin from cherrypy.lib import httputil as _httputil class CherryPyException(Exception): """A base class for CherryPy exceptions.""" pass class TimeoutError(CherryPyException): """Exception raised when Response.timed_out is detected.""" pass class InternalRedirect(CherryPyException): """Exception raised to switch to the handler for a different URL. This exception will redirect processing to another path within the site (without informing the client). Provide the new path as an argument when raising the exception. Provide any params in the querystring for the new URL. """ def __init__(self, path, query_string=''): import cherrypy self.request = cherrypy.serving.request self.query_string = query_string if '?' in path: # Separate any params included in the path path, self.query_string = path.split('?', 1) # Note that urljoin will "do the right thing" whether url is: # 1. a URL relative to root (e.g. "/dummy") # 2. a URL relative to the current path # Note that any query string will be discarded. path = _urljoin(self.request.path_info, path) # Set a 'path' member attribute so that code which traps this # error can have access to it. self.path = path CherryPyException.__init__(self, path, self.query_string) class HTTPRedirect(CherryPyException): """Exception raised when the request should be redirected. This exception will force a HTTP redirect to the URL or URL's you give it. The new URL must be passed as the first argument to the Exception, e.g., HTTPRedirect(newUrl). Multiple URLs are allowed in a list. If a URL is absolute, it will be used as-is. If it is relative, it is assumed to be relative to the current cherrypy.request.path_info. If one of the provided URL is a unicode object, it will be encoded using the default encoding or the one passed in parameter. There are multiple types of redirect, from which you can select via the ``status`` argument. If you do not provide a ``status`` arg, it defaults to 303 (or 302 if responding with HTTP/1.0). Examples:: raise cherrypy.HTTPRedirect("") raise cherrypy.HTTPRedirect("/abs/path", 307) raise cherrypy.HTTPRedirect(["path1", "path2?a=1&b=2"], 301) See :ref:`redirectingpost` for additional caveats. """ status = None """The integer HTTP status code to emit.""" urls = None """The list of URL's to emit.""" encoding = 'utf-8' """The encoding when passed urls are not native strings""" def __init__(self, urls, status=None, encoding=None): import cherrypy request = cherrypy.serving.request if isinstance(urls, text_or_bytes): urls = [urls] self.urls = [tonative(url, encoding or self.encoding) for url in urls] # RFC 2616 indicates a 301 response code fits our goal; however, # browser support for 301 is quite messy. Do 302/303 instead. See # http://www.alanflavell.org.uk/www/post-redirect.html if status is None: if request.protocol >= (1, 1): status = 303 else: status = 302 else: status = int(status) if status < 300 or status > 399: raise ValueError('status must be between 300 and 399.') self.status = status CherryPyException.__init__(self, self.urls, status) def set_response(self): """Modify cherrypy.response status, headers, and body to represent self. CherryPy uses this internally, but you can also use it to create an HTTPRedirect object and set its output without *raising* the exception. """ import cherrypy response = cherrypy.serving.response response.status = status = self.status if status in (300, 301, 302, 303, 307): response.headers['Content-Type'] = 'text/html;charset=utf-8' # "The ... URI SHOULD be given by the Location field # in the response." response.headers['Location'] = self.urls[0] # "Unless the request method was HEAD, the entity of the response # SHOULD contain a short hypertext note with a hyperlink to the # new URI(s)." msg = { 300: 'This resource can be found at ', 301: 'This resource has permanently moved to ', 302: 'This resource resides temporarily at ', 303: 'This resource can be found at ', 307: 'This resource has moved temporarily to ', }[status] msg += '%s.' msgs = [msg % (saxutils.quoteattr(u), u) for u in self.urls] response.body = ntob('
\n'.join(msgs), 'utf-8') # Previous code may have set C-L, so we have to reset it # (allow finalize to set it). response.headers.pop('Content-Length', None) elif status == 304: # Not Modified. # "The response MUST include the following header fields: # Date, unless its omission is required by section 14.18.1" # The "Date" header should have been set in Response.__init__ # "...the response SHOULD NOT include other entity-headers." for key in ('Allow', 'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-Location', 'Content-MD5', 'Content-Range', 'Content-Type', 'Expires', 'Last-Modified'): if key in response.headers: del response.headers[key] # "The 304 response MUST NOT contain a message-body." response.body = None # Previous code may have set C-L, so we have to reset it. response.headers.pop('Content-Length', None) elif status == 305: # Use Proxy. # self.urls[0] should be the URI of the proxy. response.headers['Location'] = ntob(self.urls[0], 'utf-8') response.body = None # Previous code may have set C-L, so we have to reset it. response.headers.pop('Content-Length', None) else: raise ValueError('The %s status code is unknown.' % status) def __call__(self): """Use this exception as a request.handler (raise self).""" raise self def clean_headers(status): """Remove any headers which should not apply to an error response.""" import cherrypy response = cherrypy.serving.response # Remove headers which applied to the original content, # but do not apply to the error page. respheaders = response.headers for key in ['Accept-Ranges', 'Age', 'ETag', 'Location', 'Retry-After', 'Vary', 'Content-Encoding', 'Content-Length', 'Expires', 'Content-Location', 'Content-MD5', 'Last-Modified']: if key in respheaders: del respheaders[key] if status != 416: # A server sending a response with status code 416 (Requested # range not satisfiable) SHOULD include a Content-Range field # with a byte-range-resp-spec of "*". The instance-length # specifies the current length of the selected resource. # A response with status code 206 (Partial Content) MUST NOT # include a Content-Range field with a byte-range- resp-spec of "*". if 'Content-Range' in respheaders: del respheaders['Content-Range'] class HTTPError(CherryPyException): """Exception used to return an HTTP error code (4xx-5xx) to the client. This exception can be used to automatically send a response using a http status code, with an appropriate error page. It takes an optional ``status`` argument (which must be between 400 and 599); it defaults to 500 ("Internal Server Error"). It also takes an optional ``message`` argument, which will be returned in the response body. See `RFC2616 `_ for a complete list of available error codes and when to use them. Examples:: raise cherrypy.HTTPError(403) raise cherrypy.HTTPError( "403 Forbidden", "You are not allowed to access this resource.") """ status = None """The HTTP status code. May be of type int or str (with a Reason-Phrase). """ code = None """The integer HTTP status code.""" reason = None """The HTTP Reason-Phrase string.""" def __init__(self, status=500, message=None): self.status = status try: self.code, self.reason, defaultmsg = _httputil.valid_status(status) except ValueError: raise self.__class__(500, _exc_info()[1].args[0]) if self.code < 400 or self.code > 599: raise ValueError('status must be between 400 and 599.') # See http://www.python.org/dev/peps/pep-0352/ # self.message = message self._message = message or defaultmsg CherryPyException.__init__(self, status, message) def set_response(self): """Modify cherrypy.response status, headers, and body to represent self. CherryPy uses this internally, but you can also use it to create an HTTPError object and set its output without *raising* the exception. """ import cherrypy response = cherrypy.serving.response clean_headers(self.code) # In all cases, finalize will be called after this method, # so don't bother cleaning up response values here. response.status = self.status tb = None if cherrypy.serving.request.show_tracebacks: tb = format_exc() response.headers.pop('Content-Length', None) content = self.get_error_page(self.status, traceback=tb, message=self._message) response.body = content _be_ie_unfriendly(self.code) def get_error_page(self, *args, **kwargs): return get_error_page(*args, **kwargs) def __call__(self): """Use this exception as a request.handler (raise self).""" raise self @classmethod @contextlib.contextmanager def handle(cls, exception, status=500, message=''): """Translate exception into an HTTPError.""" try: yield except exception as exc: raise cls(status, message or str(exc)) class NotFound(HTTPError): """Exception raised when a URL could not be mapped to any handler (404). This is equivalent to raising :class:`HTTPError("404 Not Found") `. """ def __init__(self, path=None): if path is None: import cherrypy request = cherrypy.serving.request path = request.script_name + request.path_info self.args = (path,) HTTPError.__init__(self, 404, "The path '%s' was not found." % path) _HTTPErrorTemplate = ''' %(status)s

%(status)s

%(message)s

%(traceback)s
Powered by CherryPy %(version)s
''' def get_error_page(status, **kwargs): """Return an HTML page, containing a pretty error response. status should be an int or a str. kwargs will be interpolated into the page template. """ import cherrypy try: code, reason, message = _httputil.valid_status(status) except ValueError: raise cherrypy.HTTPError(500, _exc_info()[1].args[0]) # We can't use setdefault here, because some # callers send None for kwarg values. if kwargs.get('status') is None: kwargs['status'] = '%s %s' % (code, reason) if kwargs.get('message') is None: kwargs['message'] = message if kwargs.get('traceback') is None: kwargs['traceback'] = '' if kwargs.get('version') is None: kwargs['version'] = cherrypy.__version__ for k, v in iteritems(kwargs): if v is None: kwargs[k] = '' else: kwargs[k] = _escape(kwargs[k]) # Use a custom template or callable for the error page? pages = cherrypy.serving.request.error_page error_page = pages.get(code) or pages.get('default') # Default template, can be overridden below. template = _HTTPErrorTemplate if error_page: try: if hasattr(error_page, '__call__'): # The caller function may be setting headers manually, # so we delegate to it completely. We may be returning # an iterator as well as a string here. # # We *must* make sure any content is not unicode. result = error_page(**kwargs) if cherrypy.lib.is_iterator(result): from cherrypy.lib.encoding import UTF8StreamEncoder return UTF8StreamEncoder(result) elif isinstance(result, six.text_type): return result.encode('utf-8') else: if not isinstance(result, bytes): raise ValueError('error page function did not ' 'return a bytestring, six.text_typeing or an ' 'iterator - returned object of type %s.' % (type(result).__name__)) return result else: # Load the template from this path. template = tonative(open(error_page, 'rb').read()) except: e = _format_exception(*_exc_info())[-1] m = kwargs['message'] if m: m += '
' m += 'In addition, the custom error page failed:\n
%s' % e kwargs['message'] = m response = cherrypy.serving.response response.headers['Content-Type'] = 'text/html;charset=utf-8' result = template % kwargs return result.encode('utf-8') _ie_friendly_error_sizes = { 400: 512, 403: 256, 404: 512, 405: 256, 406: 512, 408: 512, 409: 512, 410: 256, 500: 512, 501: 512, 505: 512, } def _be_ie_unfriendly(status): import cherrypy response = cherrypy.serving.response # For some statuses, Internet Explorer 5+ shows "friendly error # messages" instead of our response.body if the body is smaller # than a given size. Fix this by returning a body over that size # (by adding whitespace). # See http://support.microsoft.com/kb/q218155/ s = _ie_friendly_error_sizes.get(status, 0) if s: s += 1 # Since we are issuing an HTTP error status, we assume that # the entity is short, and we should just collapse it. content = response.collapse_body() l = len(content) if l and l < s: # IN ADDITION: the response must be written to IE # in one chunk or it will still get replaced! Bah. content = content + (ntob(' ') * (s - l)) response.body = content response.headers['Content-Length'] = str(len(content)) def format_exc(exc=None): """Return exc (or sys.exc_info if None), formatted.""" try: if exc is None: exc = _exc_info() if exc == (None, None, None): return '' import traceback return ''.join(traceback.format_exception(*exc)) finally: del exc def bare_error(extrabody=None): """Produce status, headers, body for a critical error. Returns a triple without calling any other questionable functions, so it should be as error-free as possible. Call it from an HTTP server if you get errors outside of the request. If extrabody is None, a friendly but rather unhelpful error message is set in the body. If extrabody is a string, it will be appended as-is to the body. """ # The whole point of this function is to be a last line-of-defense # in handling errors. That is, it must not raise any errors itself; # it cannot be allowed to fail. Therefore, don't add to it! # In particular, don't call any other CP functions. body = ntob('Unrecoverable error in the server.') if extrabody is not None: if not isinstance(extrabody, bytes): extrabody = extrabody.encode('utf-8') body += ntob('\n') + extrabody return (ntob('500 Internal Server Error'), [(ntob('Content-Type'), ntob('text/plain')), (ntob('Content-Length'), ntob(str(len(body)), 'ISO-8859-1'))], [body]) SABnzbd-2.3.2/cherrypy/_cplogging.py0000644000000000000000000004147513217005257015473 0ustar 00000000000000""" Simple config ============= Although CherryPy uses the :mod:`Python logging module `, it does so behind the scenes so that simple logging is simple, but complicated logging is still possible. "Simple" logging means that you can log to the screen (i.e. console/stdout) or to a file, and that you can easily have separate error and access log files. Here are the simplified logging settings. You use these by adding lines to your config file or dict. You should set these at either the global level or per application (see next), but generally not both. * ``log.screen``: Set this to True to have both "error" and "access" messages printed to stdout. * ``log.access_file``: Set this to an absolute filename where you want "access" messages written. * ``log.error_file``: Set this to an absolute filename where you want "error" messages written. Many events are automatically logged; to log your own application events, call :func:`cherrypy.log`. Architecture ============ Separate scopes --------------- CherryPy provides log managers at both the global and application layers. This means you can have one set of logging rules for your entire site, and another set of rules specific to each application. The global log manager is found at :func:`cherrypy.log`, and the log manager for each application is found at :attr:`app.log`. If you're inside a request, the latter is reachable from ``cherrypy.request.app.log``; if you're outside a request, you'll have to obtain a reference to the ``app``: either the return value of :func:`tree.mount()` or, if you used :func:`quickstart()` instead, via ``cherrypy.tree.apps['/']``. By default, the global logs are named "cherrypy.error" and "cherrypy.access", and the application logs are named "cherrypy.error.2378745" and "cherrypy.access.2378745" (the number is the id of the Application object). This means that the application logs "bubble up" to the site logs, so if your application has no log handlers, the site-level handlers will still log the messages. Errors vs. Access ----------------- Each log manager handles both "access" messages (one per HTTP request) and "error" messages (everything else). Note that the "error" log is not just for errors! The format of access messages is highly formalized, but the error log isn't--it receives messages from a variety of sources (including full error tracebacks, if enabled). If you are logging the access log and error log to the same source, then there is a possibility that a specially crafted error message may replicate an access log message as described in CWE-117. In this case it is the application developer's responsibility to manually escape data before using CherryPy's log() functionality, or they may create an application that is vulnerable to CWE-117. This would be achieved by using a custom handler escape any special characters, and attached as described below. Custom Handlers =============== The simple settings above work by manipulating Python's standard :mod:`logging` module. So when you need something more complex, the full power of the standard module is yours to exploit. You can borrow or create custom handlers, formats, filters, and much more. Here's an example that skips the standard FileHandler and uses a RotatingFileHandler instead: :: #python log = app.log # Remove the default FileHandlers if present. log.error_file = "" log.access_file = "" maxBytes = getattr(log, "rot_maxBytes", 10000000) backupCount = getattr(log, "rot_backupCount", 1000) # Make a new RotatingFileHandler for the error log. fname = getattr(log, "rot_error_file", "error.log") h = handlers.RotatingFileHandler(fname, 'a', maxBytes, backupCount) h.setLevel(DEBUG) h.setFormatter(_cplogging.logfmt) log.error_log.addHandler(h) # Make a new RotatingFileHandler for the access log. fname = getattr(log, "rot_access_file", "access.log") h = handlers.RotatingFileHandler(fname, 'a', maxBytes, backupCount) h.setLevel(DEBUG) h.setFormatter(_cplogging.logfmt) log.access_log.addHandler(h) The ``rot_*`` attributes are pulled straight from the application log object. Since "log.*" config entries simply set attributes on the log object, you can add custom attributes to your heart's content. Note that these handlers are used ''instead'' of the default, simple handlers outlined above (so don't set the "log.error_file" config entry, for example). """ import datetime import logging import os import sys import six import cherrypy from cherrypy import _cperror from cherrypy._cpcompat import ntob # Silence the no-handlers "warning" (stderr write!) in stdlib logging logging.Logger.manager.emittedNoHandlerWarning = 1 logfmt = logging.Formatter('%(message)s') class NullHandler(logging.Handler): """A no-op logging handler to silence the logging.lastResort handler.""" def handle(self, record): pass def emit(self, record): pass def createLock(self): self.lock = None class LogManager(object): """An object to assist both simple and advanced logging. ``cherrypy.log`` is an instance of this class. """ appid = None """The id() of the Application object which owns this log manager. If this is a global log manager, appid is None.""" error_log = None """The actual :class:`logging.Logger` instance for error messages.""" access_log = None """The actual :class:`logging.Logger` instance for access messages.""" access_log_format = ( '{h} {l} {u} {t} "{r}" {s} {b} "{f}" "{a}"' if six.PY3 else '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' ) logger_root = None """The "top-level" logger name. This string will be used as the first segment in the Logger names. The default is "cherrypy", for example, in which case the Logger names will be of the form:: cherrypy.error. cherrypy.access. """ def __init__(self, appid=None, logger_root='cherrypy'): self.logger_root = logger_root self.appid = appid if appid is None: self.error_log = logging.getLogger('%s.error' % logger_root) self.access_log = logging.getLogger('%s.access' % logger_root) else: self.error_log = logging.getLogger( '%s.error.%s' % (logger_root, appid)) self.access_log = logging.getLogger( '%s.access.%s' % (logger_root, appid)) self.error_log.setLevel(logging.INFO) self.access_log.setLevel(logging.INFO) # Silence the no-handlers "warning" (stderr write!) in stdlib logging self.error_log.addHandler(NullHandler()) self.access_log.addHandler(NullHandler()) cherrypy.engine.subscribe('graceful', self.reopen_files) def reopen_files(self): """Close and reopen all file handlers.""" for log in (self.error_log, self.access_log): for h in log.handlers: if isinstance(h, logging.FileHandler): h.acquire() h.stream.close() h.stream = open(h.baseFilename, h.mode) h.release() def error(self, msg='', context='', severity=logging.INFO, traceback=False): """Write the given ``msg`` to the error log. This is not just for errors! Applications may call this at any time to log application-specific information. If ``traceback`` is True, the traceback of the current exception (if any) will be appended to ``msg``. """ exc_info = None if traceback: exc_info = _cperror._exc_info() self.error_log.log(severity, ' '.join((self.time(), context, msg)), exc_info=exc_info) def __call__(self, *args, **kwargs): """An alias for ``error``.""" return self.error(*args, **kwargs) def access(self): """Write to the access log (in Apache/NCSA Combined Log format). See the `apache documentation `_ for format details. CherryPy calls this automatically for you. Note there are no arguments; it collects the data itself from :class:`cherrypy.request`. Like Apache started doing in 2.0.46, non-printable and other special characters in %r (and we expand that to all parts) are escaped using \\xhh sequences, where hh stands for the hexadecimal representation of the raw byte. Exceptions from this rule are " and \\, which are escaped by prepending a backslash, and all whitespace characters, which are written in their C-style notation (\\n, \\t, etc). """ request = cherrypy.serving.request remote = request.remote response = cherrypy.serving.response outheaders = response.headers inheaders = request.headers if response.output_status is None: status = '-' else: status = response.output_status.split(ntob(' '), 1)[0] if six.PY3: status = status.decode('ISO-8859-1') atoms = {'h': remote.name or remote.ip, 'l': '-', 'u': getattr(request, 'login', None) or '-', 't': self.time(), 'r': request.request_line, 's': status, 'b': dict.get(outheaders, 'Content-Length', '') or '-', 'f': dict.get(inheaders, 'Referer', ''), 'a': dict.get(inheaders, 'User-Agent', ''), 'o': dict.get(inheaders, 'Host', '-'), } if six.PY3: for k, v in atoms.items(): if not isinstance(v, str): v = str(v) v = v.replace('"', '\\"').encode('utf8') # Fortunately, repr(str) escapes unprintable chars, \n, \t, etc # and backslash for us. All we have to do is strip the quotes. v = repr(v)[2:-1] # in python 3.0 the repr of bytes (as returned by encode) # uses double \'s. But then the logger escapes them yet, again # resulting in quadruple slashes. Remove the extra one here. v = v.replace('\\\\', '\\') # Escape double-quote. atoms[k] = v try: self.access_log.log( logging.INFO, self.access_log_format.format(**atoms)) except: self(traceback=True) else: for k, v in atoms.items(): if isinstance(v, six.text_type): v = v.encode('utf8') elif not isinstance(v, str): v = str(v) # Fortunately, repr(str) escapes unprintable chars, \n, \t, etc # and backslash for us. All we have to do is strip the quotes. v = repr(v)[1:-1] # Escape double-quote. atoms[k] = v.replace('"', '\\"') try: self.access_log.log( logging.INFO, self.access_log_format % atoms) except: self(traceback=True) def time(self): """Return now() in Apache Common Log Format (no timezone).""" now = datetime.datetime.now() monthnames = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'] month = monthnames[now.month - 1].capitalize() return ('[%02d/%s/%04d:%02d:%02d:%02d]' % (now.day, month, now.year, now.hour, now.minute, now.second)) def _get_builtin_handler(self, log, key): for h in log.handlers: if getattr(h, '_cpbuiltin', None) == key: return h # ------------------------- Screen handlers ------------------------- # def _set_screen_handler(self, log, enable, stream=None): h = self._get_builtin_handler(log, 'screen') if enable: if not h: if stream is None: stream = sys.stderr h = logging.StreamHandler(stream) h.setFormatter(logfmt) h._cpbuiltin = 'screen' log.addHandler(h) elif h: log.handlers.remove(h) def _get_screen(self): h = self._get_builtin_handler has_h = h(self.error_log, 'screen') or h(self.access_log, 'screen') return bool(has_h) def _set_screen(self, newvalue): self._set_screen_handler(self.error_log, newvalue, stream=sys.stderr) self._set_screen_handler(self.access_log, newvalue, stream=sys.stdout) screen = property(_get_screen, _set_screen, doc="""Turn stderr/stdout logging on or off. If you set this to True, it'll add the appropriate StreamHandler for you. If you set it to False, it will remove the handler. """) # -------------------------- File handlers -------------------------- # def _add_builtin_file_handler(self, log, fname): h = logging.FileHandler(fname) h.setFormatter(logfmt) h._cpbuiltin = 'file' log.addHandler(h) def _set_file_handler(self, log, filename): h = self._get_builtin_handler(log, 'file') if filename: if h: if h.baseFilename != os.path.abspath(filename): h.close() log.handlers.remove(h) self._add_builtin_file_handler(log, filename) else: self._add_builtin_file_handler(log, filename) else: if h: h.close() log.handlers.remove(h) def _get_error_file(self): h = self._get_builtin_handler(self.error_log, 'file') if h: return h.baseFilename return '' def _set_error_file(self, newvalue): self._set_file_handler(self.error_log, newvalue) error_file = property(_get_error_file, _set_error_file, doc="""The filename for self.error_log. If you set this to a string, it'll add the appropriate FileHandler for you. If you set it to ``None`` or ``''``, it will remove the handler. """) def _get_access_file(self): h = self._get_builtin_handler(self.access_log, 'file') if h: return h.baseFilename return '' def _set_access_file(self, newvalue): self._set_file_handler(self.access_log, newvalue) access_file = property(_get_access_file, _set_access_file, doc="""The filename for self.access_log. If you set this to a string, it'll add the appropriate FileHandler for you. If you set it to ``None`` or ``''``, it will remove the handler. """) # ------------------------- WSGI handlers ------------------------- # def _set_wsgi_handler(self, log, enable): h = self._get_builtin_handler(log, 'wsgi') if enable: if not h: h = WSGIErrorHandler() h.setFormatter(logfmt) h._cpbuiltin = 'wsgi' log.addHandler(h) elif h: log.handlers.remove(h) def _get_wsgi(self): return bool(self._get_builtin_handler(self.error_log, 'wsgi')) def _set_wsgi(self, newvalue): self._set_wsgi_handler(self.error_log, newvalue) wsgi = property(_get_wsgi, _set_wsgi, doc="""Write errors to wsgi.errors. If you set this to True, it'll add the appropriate :class:`WSGIErrorHandler` for you (which writes errors to ``wsgi.errors``). If you set it to False, it will remove the handler. """) class WSGIErrorHandler(logging.Handler): "A handler class which writes logging records to environ['wsgi.errors']." def flush(self): """Flushes the stream.""" try: stream = cherrypy.serving.request.wsgi_environ.get('wsgi.errors') except (AttributeError, KeyError): pass else: stream.flush() def emit(self, record): """Emit a record.""" try: stream = cherrypy.serving.request.wsgi_environ.get('wsgi.errors') except (AttributeError, KeyError): pass else: try: msg = self.format(record) fs = '%s\n' import types # if no unicode support... if not hasattr(types, 'UnicodeType'): stream.write(fs % msg) else: try: stream.write(fs % msg) except UnicodeError: stream.write(fs % msg.encode('UTF-8')) self.flush() except: self.handleError(record) SABnzbd-2.3.2/cherrypy/_cpmodpy.py0000644000000000000000000002562613217005257015175 0ustar 00000000000000"""Native adapter for serving CherryPy via mod_python Basic usage: ########################################## # Application in a module called myapp.py ########################################## import cherrypy class Root: @cherrypy.expose def index(self): return 'Hi there, Ho there, Hey there' # We will use this method from the mod_python configuration # as the entry point to our application def setup_server(): cherrypy.tree.mount(Root()) cherrypy.config.update({'environment': 'production', 'log.screen': False, 'show_tracebacks': False}) ########################################## # mod_python settings for apache2 # This should reside in your httpd.conf # or a file that will be loaded at # apache startup ########################################## # Start DocumentRoot "/" Listen 8080 LoadModule python_module /usr/lib/apache2/modules/mod_python.so PythonPath "sys.path+['/path/to/my/application']" SetHandler python-program PythonHandler cherrypy._cpmodpy::handler PythonOption cherrypy.setup myapp::setup_server PythonDebug On # End The actual path to your mod_python.so is dependent on your environment. In this case we suppose a global mod_python installation on a Linux distribution such as Ubuntu. We do set the PythonPath configuration setting so that your application can be found by from the user running the apache2 instance. Of course if your application resides in the global site-package this won't be needed. Then restart apache2 and access http://127.0.0.1:8080 """ import io import logging import os import re import sys import cherrypy from cherrypy._cpcompat import copyitems, ntob from cherrypy._cperror import format_exc, bare_error from cherrypy.lib import httputil # ------------------------------ Request-handling def setup(req): from mod_python import apache # Run any setup functions defined by a "PythonOption cherrypy.setup" # directive. options = req.get_options() if 'cherrypy.setup' in options: for function in options['cherrypy.setup'].split(): atoms = function.split('::', 1) if len(atoms) == 1: mod = __import__(atoms[0], globals(), locals()) else: modname, fname = atoms mod = __import__(modname, globals(), locals(), [fname]) func = getattr(mod, fname) func() cherrypy.config.update({'log.screen': False, 'tools.ignore_headers.on': True, 'tools.ignore_headers.headers': ['Range'], }) engine = cherrypy.engine if hasattr(engine, 'signal_handler'): engine.signal_handler.unsubscribe() if hasattr(engine, 'console_control_handler'): engine.console_control_handler.unsubscribe() engine.autoreload.unsubscribe() cherrypy.server.unsubscribe() def _log(msg, level): newlevel = apache.APLOG_ERR if logging.DEBUG >= level: newlevel = apache.APLOG_DEBUG elif logging.INFO >= level: newlevel = apache.APLOG_INFO elif logging.WARNING >= level: newlevel = apache.APLOG_WARNING # On Windows, req.server is required or the msg will vanish. See # http://www.modpython.org/pipermail/mod_python/2003-October/014291.html # Also, "When server is not specified...LogLevel does not apply..." apache.log_error(msg, newlevel, req.server) engine.subscribe('log', _log) engine.start() def cherrypy_cleanup(data): engine.exit() try: # apache.register_cleanup wasn't available until 3.1.4. apache.register_cleanup(cherrypy_cleanup) except AttributeError: req.server.register_cleanup(req, cherrypy_cleanup) class _ReadOnlyRequest: expose = ('read', 'readline', 'readlines') def __init__(self, req): for method in self.expose: self.__dict__[method] = getattr(req, method) recursive = False _isSetUp = False def handler(req): from mod_python import apache try: global _isSetUp if not _isSetUp: setup(req) _isSetUp = True # Obtain a Request object from CherryPy local = req.connection.local_addr local = httputil.Host( local[0], local[1], req.connection.local_host or '') remote = req.connection.remote_addr remote = httputil.Host( remote[0], remote[1], req.connection.remote_host or '') scheme = req.parsed_uri[0] or 'http' req.get_basic_auth_pw() try: # apache.mpm_query only became available in mod_python 3.1 q = apache.mpm_query threaded = q(apache.AP_MPMQ_IS_THREADED) forked = q(apache.AP_MPMQ_IS_FORKED) except AttributeError: bad_value = ("You must provide a PythonOption '%s', " "either 'on' or 'off', when running a version " 'of mod_python < 3.1') threaded = options.get('multithread', '').lower() if threaded == 'on': threaded = True elif threaded == 'off': threaded = False else: raise ValueError(bad_value % 'multithread') forked = options.get('multiprocess', '').lower() if forked == 'on': forked = True elif forked == 'off': forked = False else: raise ValueError(bad_value % 'multiprocess') sn = cherrypy.tree.script_name(req.uri or '/') if sn is None: send_response(req, '404 Not Found', [], '') else: app = cherrypy.tree.apps[sn] method = req.method path = req.uri qs = req.args or '' reqproto = req.protocol headers = copyitems(req.headers_in) rfile = _ReadOnlyRequest(req) prev = None try: redirections = [] while True: request, response = app.get_serving(local, remote, scheme, 'HTTP/1.1') request.login = req.user request.multithread = bool(threaded) request.multiprocess = bool(forked) request.app = app request.prev = prev # Run the CherryPy Request object and obtain the response try: request.run(method, path, qs, reqproto, headers, rfile) break except cherrypy.InternalRedirect: ir = sys.exc_info()[1] app.release_serving() prev = request if not recursive: if ir.path in redirections: raise RuntimeError( 'InternalRedirector visited the same URL ' 'twice: %r' % ir.path) else: # Add the *previous* path_info + qs to # redirections. if qs: qs = '?' + qs redirections.append(sn + path + qs) # Munge environment and try again. method = 'GET' path = ir.path qs = ir.query_string rfile = io.BytesIO() send_response( req, response.output_status, response.header_list, response.body, response.stream) finally: app.release_serving() except: tb = format_exc() cherrypy.log(tb, 'MOD_PYTHON', severity=logging.ERROR) s, h, b = bare_error() send_response(req, s, h, b) return apache.OK def send_response(req, status, headers, body, stream=False): # Set response status req.status = int(status[:3]) # Set response headers req.content_type = 'text/plain' for header, value in headers: if header.lower() == 'content-type': req.content_type = value continue req.headers_out.add(header, value) if stream: # Flush now so the status and headers are sent immediately. req.flush() # Set response body if isinstance(body, text_or_bytes): req.write(body) else: for seg in body: req.write(seg) # --------------- Startup tools for CherryPy + mod_python --------------- # try: import subprocess def popen(fullcmd): p = subprocess.Popen(fullcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True) return p.stdout except ImportError: def popen(fullcmd): pipein, pipeout = os.popen4(fullcmd) return pipeout def read_process(cmd, args=''): fullcmd = '%s %s' % (cmd, args) pipeout = popen(fullcmd) try: firstline = pipeout.readline() cmd_not_found = re.search( ntob('(not recognized|No such file|not found)'), firstline, re.IGNORECASE ) if cmd_not_found: raise IOError('%s must be on your system path.' % cmd) output = firstline + pipeout.read() finally: pipeout.close() return output class ModPythonServer(object): template = """ # Apache2 server configuration file for running CherryPy with mod_python. DocumentRoot "/" Listen %(port)s LoadModule python_module modules/mod_python.so SetHandler python-program PythonHandler %(handler)s PythonDebug On %(opts)s """ def __init__(self, loc='/', port=80, opts=None, apache_path='apache', handler='cherrypy._cpmodpy::handler'): self.loc = loc self.port = port self.opts = opts self.apache_path = apache_path self.handler = handler def start(self): opts = ''.join([' PythonOption %s %s\n' % (k, v) for k, v in self.opts]) conf_data = self.template % {'port': self.port, 'loc': self.loc, 'opts': opts, 'handler': self.handler, } mpconf = os.path.join(os.path.dirname(__file__), 'cpmodpy.conf') f = open(mpconf, 'wb') try: f.write(conf_data) finally: f.close() response = read_process(self.apache_path, '-k start -f %s' % mpconf) self.ready = True return response def stop(self): os.popen('apache -k stop') self.ready = False SABnzbd-2.3.2/cherrypy/_cpnative_server.py0000644000000000000000000001352613217005257016715 0ustar 00000000000000"""Native adapter for serving CherryPy via its builtin server.""" import logging import sys import io import cherrypy from cherrypy._cperror import format_exc, bare_error from cherrypy.lib import httputil from cherrypy import wsgiserver class NativeGateway(wsgiserver.Gateway): recursive = False def respond(self): req = self.req try: # Obtain a Request object from CherryPy local = req.server.bind_addr local = httputil.Host(local[0], local[1], '') remote = req.conn.remote_addr, req.conn.remote_port remote = httputil.Host(remote[0], remote[1], '') scheme = req.scheme sn = cherrypy.tree.script_name(req.uri or '/') if sn is None: self.send_response('404 Not Found', [], ['']) else: app = cherrypy.tree.apps[sn] method = req.method path = req.path qs = req.qs or '' headers = req.inheaders.items() rfile = req.rfile prev = None try: redirections = [] while True: request, response = app.get_serving( local, remote, scheme, 'HTTP/1.1') request.multithread = True request.multiprocess = False request.app = app request.prev = prev # Run the CherryPy Request object and obtain the # response try: request.run(method, path, qs, req.request_protocol, headers, rfile) break except cherrypy.InternalRedirect: ir = sys.exc_info()[1] app.release_serving() prev = request if not self.recursive: if ir.path in redirections: raise RuntimeError( 'InternalRedirector visited the same ' 'URL twice: %r' % ir.path) else: # Add the *previous* path_info + qs to # redirections. if qs: qs = '?' + qs redirections.append(sn + path + qs) # Munge environment and try again. method = 'GET' path = ir.path qs = ir.query_string rfile = io.BytesIO() self.send_response( response.output_status, response.header_list, response.body) finally: app.release_serving() except: tb = format_exc() # print tb cherrypy.log(tb, 'NATIVE_ADAPTER', severity=logging.ERROR) s, h, b = bare_error() self.send_response(s, h, b) def send_response(self, status, headers, body): req = self.req # Set response status req.status = str(status or '500 Server Error') # Set response headers for header, value in headers: req.outheaders.append((header, value)) if (req.ready and not req.sent_headers): req.sent_headers = True req.send_headers() # Set response body for seg in body: req.write(seg) class CPHTTPServer(wsgiserver.HTTPServer): """Wrapper for wsgiserver.HTTPServer. wsgiserver has been designed to not reference CherryPy in any way, so that it can be used in other frameworks and applications. Therefore, we wrap it here, so we can apply some attributes from config -> cherrypy.server -> HTTPServer. """ def __init__(self, server_adapter=cherrypy.server): self.server_adapter = server_adapter server_name = (self.server_adapter.socket_host or self.server_adapter.socket_file or None) wsgiserver.HTTPServer.__init__( self, server_adapter.bind_addr, NativeGateway, minthreads=server_adapter.thread_pool, maxthreads=server_adapter.thread_pool_max, server_name=server_name) self.max_request_header_size = ( self.server_adapter.max_request_header_size or 0) self.max_request_body_size = ( self.server_adapter.max_request_body_size or 0) self.request_queue_size = self.server_adapter.socket_queue_size self.timeout = self.server_adapter.socket_timeout self.shutdown_timeout = self.server_adapter.shutdown_timeout self.protocol = self.server_adapter.protocol_version self.nodelay = self.server_adapter.nodelay ssl_module = self.server_adapter.ssl_module or 'pyopenssl' if self.server_adapter.ssl_context: adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module) self.ssl_adapter = adapter_class( self.server_adapter.ssl_certificate, self.server_adapter.ssl_private_key, self.server_adapter.ssl_certificate_chain) self.ssl_adapter.context = self.server_adapter.ssl_context elif self.server_adapter.ssl_certificate: adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module) self.ssl_adapter = adapter_class( self.server_adapter.ssl_certificate, self.server_adapter.ssl_private_key, self.server_adapter.ssl_certificate_chain) SABnzbd-2.3.2/cherrypy/_cpreqbody.py0000644000000000000000000011055313217005257015504 0ustar 00000000000000"""Request body processing for CherryPy. .. versionadded:: 3.2 Application authors have complete control over the parsing of HTTP request entities. In short, :attr:`cherrypy.request.body` is now always set to an instance of :class:`RequestBody`, and *that* class is a subclass of :class:`Entity`. When an HTTP request includes an entity body, it is often desirable to provide that information to applications in a form other than the raw bytes. Different content types demand different approaches. Examples: * For a GIF file, we want the raw bytes in a stream. * An HTML form is better parsed into its component fields, and each text field decoded from bytes to unicode. * A JSON body should be deserialized into a Python dict or list. When the request contains a Content-Type header, the media type is used as a key to look up a value in the :attr:`request.body.processors` dict. If the full media type is not found, then the major type is tried; for example, if no processor is found for the 'image/jpeg' type, then we look for a processor for the 'image' types altogether. If neither the full type nor the major type has a matching processor, then a default processor is used (:func:`default_proc`). For most types, this means no processing is done, and the body is left unread as a raw byte stream. Processors are configurable in an 'on_start_resource' hook. Some processors, especially those for the 'text' types, attempt to decode bytes to unicode. If the Content-Type request header includes a 'charset' parameter, this is used to decode the entity. Otherwise, one or more default charsets may be attempted, although this decision is up to each processor. If a processor successfully decodes an Entity or Part, it should set the :attr:`charset` attribute on the Entity or Part to the name of the successful charset, so that applications can easily re-encode or transcode the value if they wish. If the Content-Type of the request entity is of major type 'multipart', then the above parsing process, and possibly a decoding process, is performed for each part. For both the full entity and multipart parts, a Content-Disposition header may be used to fill :attr:`name` and :attr:`filename` attributes on the request.body or the Part. .. _custombodyprocessors: Custom Processors ================= You can add your own processors for any specific or major MIME type. Simply add it to the :attr:`processors` dict in a hook/tool that runs at ``on_start_resource`` or ``before_request_body``. Here's the built-in JSON tool for an example:: def json_in(force=True, debug=False): request = cherrypy.serving.request def json_processor(entity): \"""Read application/json data into request.json.\""" if not entity.headers.get("Content-Length", ""): raise cherrypy.HTTPError(411) body = entity.fp.read() try: request.json = json_decode(body) except ValueError: raise cherrypy.HTTPError(400, 'Invalid JSON document') if force: request.body.processors.clear() request.body.default_proc = cherrypy.HTTPError( 415, 'Expected an application/json content type') request.body.processors['application/json'] = json_processor We begin by defining a new ``json_processor`` function to stick in the ``processors`` dictionary. All processor functions take a single argument, the ``Entity`` instance they are to process. It will be called whenever a request is received (for those URI's where the tool is turned on) which has a ``Content-Type`` of "application/json". First, it checks for a valid ``Content-Length`` (raising 411 if not valid), then reads the remaining bytes on the socket. The ``fp`` object knows its own length, so it won't hang waiting for data that never arrives. It will return when all data has been read. Then, we decode those bytes using Python's built-in ``json`` module, and stick the decoded result onto ``request.json`` . If it cannot be decoded, we raise 400. If the "force" argument is True (the default), the ``Tool`` clears the ``processors`` dict so that request entities of other ``Content-Types`` aren't parsed at all. Since there's no entry for those invalid MIME types, the ``default_proc`` method of ``cherrypy.request.body`` is called. But this does nothing by default (usually to provide the page handler an opportunity to handle it.) But in our case, we want to raise 415, so we replace ``request.body.default_proc`` with the error (``HTTPError`` instances, when called, raise themselves). If we were defining a custom processor, we can do so without making a ``Tool``. Just add the config entry:: request.body.processors = {'application/json': json_processor} Note that you can only replace the ``processors`` dict wholesale this way, not update the existing one. """ try: from io import DEFAULT_BUFFER_SIZE except ImportError: DEFAULT_BUFFER_SIZE = 8192 import re import sys import tempfile try: from urllib import unquote_plus except ImportError: def unquote_plus(bs): """Bytes version of urllib.parse.unquote_plus.""" bs = bs.replace(ntob('+'), ntob(' ')) atoms = bs.split(ntob('%')) for i in range(1, len(atoms)): item = atoms[i] try: pct = int(item[:2], 16) atoms[i] = bytes([pct]) + item[2:] except ValueError: pass return ntob('').join(atoms) import cherrypy from cherrypy._cpcompat import text_or_bytes, ntob, ntou from cherrypy.lib import httputil # ------------------------------- Processors -------------------------------- # def process_urlencoded(entity): """Read application/x-www-form-urlencoded data into entity.params.""" qs = entity.fp.read() for charset in entity.attempt_charsets: try: params = {} for aparam in qs.split(ntob('&')): for pair in aparam.split(ntob(';')): if not pair: continue atoms = pair.split(ntob('='), 1) if len(atoms) == 1: atoms.append(ntob('')) key = unquote_plus(atoms[0]).decode(charset) value = unquote_plus(atoms[1]).decode(charset) if key in params: if not isinstance(params[key], list): params[key] = [params[key]] params[key].append(value) else: params[key] = value except UnicodeDecodeError: pass else: entity.charset = charset break else: raise cherrypy.HTTPError( 400, 'The request entity could not be decoded. The following ' 'charsets were attempted: %s' % repr(entity.attempt_charsets)) # Now that all values have been successfully parsed and decoded, # apply them to the entity.params dict. for key, value in params.items(): if key in entity.params: if not isinstance(entity.params[key], list): entity.params[key] = [entity.params[key]] entity.params[key].append(value) else: entity.params[key] = value def process_multipart(entity): """Read all multipart parts into entity.parts.""" ib = '' if 'boundary' in entity.content_type.params: # http://tools.ietf.org/html/rfc2046#section-5.1.1 # "The grammar for parameters on the Content-type field is such that it # is often necessary to enclose the boundary parameter values in quotes # on the Content-type line" ib = entity.content_type.params['boundary'].strip('"') if not re.match('^[ -~]{0,200}[!-~]$', ib): raise ValueError('Invalid boundary in multipart form: %r' % (ib,)) ib = ('--' + ib).encode('ascii') # Find the first marker while True: b = entity.readline() if not b: return b = b.strip() if b == ib: break # Read all parts while True: part = entity.part_class.from_fp(entity.fp, ib) entity.parts.append(part) part.process() if part.fp.done: break def process_multipart_form_data(entity): """Read all multipart/form-data parts into entity.parts or entity.params. """ process_multipart(entity) kept_parts = [] for part in entity.parts: if part.name is None: kept_parts.append(part) else: if part.filename is None: # It's a regular field value = part.fullvalue() else: # It's a file upload. Retain the whole part so consumer code # has access to its .file and .filename attributes. value = part if part.name in entity.params: if not isinstance(entity.params[part.name], list): entity.params[part.name] = [entity.params[part.name]] entity.params[part.name].append(value) else: entity.params[part.name] = value entity.parts = kept_parts def _old_process_multipart(entity): """The behavior of 3.2 and lower. Deprecated and will be changed in 3.3.""" process_multipart(entity) params = entity.params for part in entity.parts: if part.name is None: key = ntou('parts') else: key = part.name if part.filename is None: # It's a regular field value = part.fullvalue() else: # It's a file upload. Retain the whole part so consumer code # has access to its .file and .filename attributes. value = part if key in params: if not isinstance(params[key], list): params[key] = [params[key]] params[key].append(value) else: params[key] = value # -------------------------------- Entities --------------------------------- # class Entity(object): """An HTTP request body, or MIME multipart body. This class collects information about the HTTP request entity. When a given entity is of MIME type "multipart", each part is parsed into its own Entity instance, and the set of parts stored in :attr:`entity.parts`. Between the ``before_request_body`` and ``before_handler`` tools, CherryPy tries to process the request body (if any) by calling :func:`request.body.process`. This uses the ``content_type`` of the Entity to look up a suitable processor in :attr:`Entity.processors`, a dict. If a matching processor cannot be found for the complete Content-Type, it tries again using the major type. For example, if a request with an entity of type "image/jpeg" arrives, but no processor can be found for that complete type, then one is sought for the major type "image". If a processor is still not found, then the :func:`default_proc` method of the Entity is called (which does nothing by default; you can override this too). CherryPy includes processors for the "application/x-www-form-urlencoded" type, the "multipart/form-data" type, and the "multipart" major type. CherryPy 3.2 processes these types almost exactly as older versions. Parts are passed as arguments to the page handler using their ``Content-Disposition.name`` if given, otherwise in a generic "parts" argument. Each such part is either a string, or the :class:`Part` itself if it's a file. (In this case it will have ``file`` and ``filename`` attributes, or possibly a ``value`` attribute). Each Part is itself a subclass of Entity, and has its own ``process`` method and ``processors`` dict. There is a separate processor for the "multipart" major type which is more flexible, and simply stores all multipart parts in :attr:`request.body.parts`. You can enable it with:: cherrypy.request.body.processors['multipart'] = _cpreqbody.process_multipart in an ``on_start_resource`` tool. """ # http://tools.ietf.org/html/rfc2046#section-4.1.2: # "The default character set, which must be assumed in the # absence of a charset parameter, is US-ASCII." # However, many browsers send data in utf-8 with no charset. attempt_charsets = ['utf-8'] """A list of strings, each of which should be a known encoding. When the Content-Type of the request body warrants it, each of the given encodings will be tried in order. The first one to successfully decode the entity without raising an error is stored as :attr:`entity.charset`. This defaults to ``['utf-8']`` (plus 'ISO-8859-1' for "text/\*" types, as required by `HTTP/1.1 `_), but ``['us-ascii', 'utf-8']`` for multipart parts. """ charset = None """The successful decoding; see "attempt_charsets" above.""" content_type = None """The value of the Content-Type request header. If the Entity is part of a multipart payload, this will be the Content-Type given in the MIME headers for this part. """ default_content_type = 'application/x-www-form-urlencoded' """This defines a default ``Content-Type`` to use if no Content-Type header is given. The empty string is used for RequestBody, which results in the request body not being read or parsed at all. This is by design; a missing ``Content-Type`` header in the HTTP request entity is an error at best, and a security hole at worst. For multipart parts, however, the MIME spec declares that a part with no Content-Type defaults to "text/plain" (see :class:`Part`). """ filename = None """The ``Content-Disposition.filename`` header, if available.""" fp = None """The readable socket file object.""" headers = None """A dict of request/multipart header names and values. This is a copy of the ``request.headers`` for the ``request.body``; for multipart parts, it is the set of headers for that part. """ length = None """The value of the ``Content-Length`` header, if provided.""" name = None """The "name" parameter of the ``Content-Disposition`` header, if any.""" params = None """ If the request Content-Type is 'application/x-www-form-urlencoded' or multipart, this will be a dict of the params pulled from the entity body; that is, it will be the portion of request.params that come from the message body (sometimes called "POST params", although they can be sent with various HTTP method verbs). This value is set between the 'before_request_body' and 'before_handler' hooks (assuming that process_request_body is True).""" processors = {'application/x-www-form-urlencoded': process_urlencoded, 'multipart/form-data': process_multipart_form_data, 'multipart': process_multipart, } """A dict of Content-Type names to processor methods.""" parts = None """A list of Part instances if ``Content-Type`` is of major type "multipart".""" part_class = None """The class used for multipart parts. You can replace this with custom subclasses to alter the processing of multipart parts. """ def __init__(self, fp, headers, params=None, parts=None): # Make an instance-specific copy of the class processors # so Tools, etc. can replace them per-request. self.processors = self.processors.copy() self.fp = fp self.headers = headers if params is None: params = {} self.params = params if parts is None: parts = [] self.parts = parts # Content-Type self.content_type = headers.elements('Content-Type') if self.content_type: self.content_type = self.content_type[0] else: self.content_type = httputil.HeaderElement.from_str( self.default_content_type) # Copy the class 'attempt_charsets', prepending any Content-Type # charset dec = self.content_type.params.get('charset', None) if dec: self.attempt_charsets = [dec] + [c for c in self.attempt_charsets if c != dec] else: self.attempt_charsets = self.attempt_charsets[:] # Length self.length = None clen = headers.get('Content-Length', None) # If Transfer-Encoding is 'chunked', ignore any Content-Length. if ( clen is not None and 'chunked' not in headers.get('Transfer-Encoding', '') ): try: self.length = int(clen) except ValueError: pass # Content-Disposition self.name = None self.filename = None disp = headers.elements('Content-Disposition') if disp: disp = disp[0] if 'name' in disp.params: self.name = disp.params['name'] if self.name.startswith('"') and self.name.endswith('"'): self.name = self.name[1:-1] if 'filename' in disp.params: self.filename = disp.params['filename'] if ( self.filename.startswith('"') and self.filename.endswith('"') ): self.filename = self.filename[1:-1] # The 'type' attribute is deprecated in 3.2; remove it in 3.3. type = property( lambda self: self.content_type, doc='A deprecated alias for ' ':attr:`content_type`.' ) def read(self, size=None, fp_out=None): return self.fp.read(size, fp_out) def readline(self, size=None): return self.fp.readline(size) def readlines(self, sizehint=None): return self.fp.readlines(sizehint) def __iter__(self): return self def __next__(self): line = self.readline() if not line: raise StopIteration return line def next(self): return self.__next__() def read_into_file(self, fp_out=None): """Read the request body into fp_out (or make_file() if None). Return fp_out. """ if fp_out is None: fp_out = self.make_file() self.read(fp_out=fp_out) return fp_out def make_file(self): """Return a file-like object into which the request body will be read. By default, this will return a TemporaryFile. Override as needed. See also :attr:`cherrypy._cpreqbody.Part.maxrambytes`.""" return tempfile.TemporaryFile() def fullvalue(self): """Return this entity as a string, whether stored in a file or not.""" if self.file: # It was stored in a tempfile. Read it. self.file.seek(0) value = self.file.read() self.file.seek(0) else: value = self.value value = self.decode_entity(value) return value def decode_entity(self , value): """Return a given byte encoded value as a string""" for charset in self.attempt_charsets: try: value = value.decode(charset) except UnicodeDecodeError: pass else: self.charset = charset return value else: raise cherrypy.HTTPError( 400, 'The request entity could not be decoded. The following ' 'charsets were attempted: %s' % repr(self.attempt_charsets) ) def process(self): """Execute the best-match processor for the given media type.""" proc = None ct = self.content_type.value try: proc = self.processors[ct] except KeyError: toptype = ct.split('/', 1)[0] try: proc = self.processors[toptype] except KeyError: pass if proc is None: self.default_proc() else: proc(self) def default_proc(self): """Called if a more-specific processor is not found for the ``Content-Type``. """ # Leave the fp alone for someone else to read. This works fine # for request.body, but the Part subclasses need to override this # so they can move on to the next part. pass class Part(Entity): """A MIME part entity, part of a multipart entity.""" # "The default character set, which must be assumed in the absence of a # charset parameter, is US-ASCII." attempt_charsets = ['us-ascii', 'utf-8'] """A list of strings, each of which should be a known encoding. When the Content-Type of the request body warrants it, each of the given encodings will be tried in order. The first one to successfully decode the entity without raising an error is stored as :attr:`entity.charset`. This defaults to ``['utf-8']`` (plus 'ISO-8859-1' for "text/\*" types, as required by `HTTP/1.1 `_), but ``['us-ascii', 'utf-8']`` for multipart parts. """ boundary = None """The MIME multipart boundary.""" default_content_type = 'text/plain' """This defines a default ``Content-Type`` to use if no Content-Type header is given. The empty string is used for RequestBody, which results in the request body not being read or parsed at all. This is by design; a missing ``Content-Type`` header in the HTTP request entity is an error at best, and a security hole at worst. For multipart parts, however (this class), the MIME spec declares that a part with no Content-Type defaults to "text/plain". """ # This is the default in stdlib cgi. We may want to increase it. maxrambytes = 1000 """The threshold of bytes after which point the ``Part`` will store its data in a file (generated by :func:`make_file`) instead of a string. Defaults to 1000, just like the :mod:`cgi` module in Python's standard library. """ def __init__(self, fp, headers, boundary): Entity.__init__(self, fp, headers) self.boundary = boundary self.file = None self.value = None @classmethod def from_fp(cls, fp, boundary): headers = cls.read_headers(fp) return cls(fp, headers, boundary) @classmethod def read_headers(cls, fp): headers = httputil.HeaderMap() while True: line = fp.readline() if not line: # No more data--illegal end of headers raise EOFError('Illegal end of headers.') if line == ntob('\r\n') or line == ntob('\n'): # Normal end of headers break if not line.endswith(ntob('\n')): raise ValueError("MIME requires CRLF terminators: %r" % line) if line[0] in ntob(' \t'): # It's a continuation line. v = line.strip().decode('ISO-8859-1') else: k, v = line.split(ntob(':'), 1) k = k.strip().decode('ISO-8859-1') v = v.strip().decode('ISO-8859-1') existing = headers.get(k) if existing: v = ', '.join((existing, v)) headers[k] = v return headers def read_lines_to_boundary(self, fp_out=None): """Read bytes from self.fp and return or write them to a file. If the 'fp_out' argument is None (the default), all bytes read are returned in a single byte string. If the 'fp_out' argument is not None, it must be a file-like object that supports the 'write' method; all bytes read will be written to the fp, and that fp is returned. """ endmarker = self.boundary + ntob('--') delim = ntob('') prev_lf = True lines = [] seen = 0 while True: line = self.fp.readline(1 << 16) if not line: raise EOFError('Illegal end of multipart body.') if line.startswith(ntob('--')) and prev_lf: strippedline = line.strip() if strippedline == self.boundary: break if strippedline == endmarker: self.fp.finish() break line = delim + line if line.endswith(ntob('\r\n')): delim = ntob('\r\n') line = line[:-2] prev_lf = True elif line.endswith(ntob('\n')): delim = ntob('\n') line = line[:-1] prev_lf = True else: delim = ntob('') prev_lf = False if fp_out is None: lines.append(line) seen += len(line) if seen > self.maxrambytes: fp_out = self.make_file() for line in lines: fp_out.write(line) else: fp_out.write(line) if fp_out is None: result = ntob('').join(lines) return result else: fp_out.seek(0) return fp_out def default_proc(self): """Called if a more-specific processor is not found for the ``Content-Type``. """ if self.filename: # Always read into a file if a .filename was given. self.file = self.read_into_file() else: result = self.read_lines_to_boundary() if isinstance(result, text_or_bytes): self.value = result else: self.file = result def read_into_file(self, fp_out=None): """Read the request body into fp_out (or make_file() if None). Return fp_out. """ if fp_out is None: fp_out = self.make_file() self.read_lines_to_boundary(fp_out=fp_out) return fp_out Entity.part_class = Part inf = float('inf') comma_separated_headers = [ 'Accept', 'Accept-Charset', 'Accept-Encoding', 'Accept-Language', 'Accept-Ranges', 'Allow', 'Cache-Control', 'Connection', 'Content-Encoding', 'Content-Language', 'Expect', 'If-Match', 'If-None-Match', 'Pragma', 'Proxy-Authenticate', 'Te', 'Trailer', 'Transfer-Encoding', 'Upgrade', 'Vary', 'Via', 'Warning', 'Www-Authenticate' ] class SizedReader: def __init__(self, fp, length, maxbytes, bufsize=DEFAULT_BUFFER_SIZE, has_trailers=False): # Wrap our fp in a buffer so peek() works self.fp = fp self.length = length self.maxbytes = maxbytes self.buffer = ntob('') self.bufsize = bufsize self.bytes_read = 0 self.done = False self.has_trailers = has_trailers def read(self, size=None, fp_out=None): """Read bytes from the request body and return or write them to a file. A number of bytes less than or equal to the 'size' argument are read off the socket. The actual number of bytes read are tracked in self.bytes_read. The number may be smaller than 'size' when 1) the client sends fewer bytes, 2) the 'Content-Length' request header specifies fewer bytes than requested, or 3) the number of bytes read exceeds self.maxbytes (in which case, 413 is raised). If the 'fp_out' argument is None (the default), all bytes read are returned in a single byte string. If the 'fp_out' argument is not None, it must be a file-like object that supports the 'write' method; all bytes read will be written to the fp, and None is returned. """ if self.length is None: if size is None: remaining = inf else: remaining = size else: remaining = self.length - self.bytes_read if size and size < remaining: remaining = size if remaining == 0: self.finish() if fp_out is None: return ntob('') else: return None chunks = [] # Read bytes from the buffer. if self.buffer: if remaining is inf: data = self.buffer self.buffer = ntob('') else: data = self.buffer[:remaining] self.buffer = self.buffer[remaining:] datalen = len(data) remaining -= datalen # Check lengths. self.bytes_read += datalen if self.maxbytes and self.bytes_read > self.maxbytes: raise cherrypy.HTTPError(413) # Store the data. if fp_out is None: chunks.append(data) else: fp_out.write(data) # Read bytes from the socket. while remaining > 0: chunksize = min(remaining, self.bufsize) try: data = self.fp.read(chunksize) except Exception: e = sys.exc_info()[1] if e.__class__.__name__ == 'MaxSizeExceeded': # Post data is too big raise cherrypy.HTTPError( 413, 'Maximum request length: %r' % e.args[1]) else: raise if not data: self.finish() break datalen = len(data) remaining -= datalen # Check lengths. self.bytes_read += datalen if self.maxbytes and self.bytes_read > self.maxbytes: raise cherrypy.HTTPError(413) # Store the data. if fp_out is None: chunks.append(data) else: fp_out.write(data) if fp_out is None: return ntob('').join(chunks) def readline(self, size=None): """Read a line from the request body and return it.""" chunks = [] while size is None or size > 0: chunksize = self.bufsize if size is not None and size < self.bufsize: chunksize = size data = self.read(chunksize) if not data: break pos = data.find(ntob('\n')) + 1 if pos: chunks.append(data[:pos]) remainder = data[pos:] self.buffer += remainder self.bytes_read -= len(remainder) break else: chunks.append(data) return ntob('').join(chunks) def readlines(self, sizehint=None): """Read lines from the request body and return them.""" if self.length is not None: if sizehint is None: sizehint = self.length - self.bytes_read else: sizehint = min(sizehint, self.length - self.bytes_read) lines = [] seen = 0 while True: line = self.readline() if not line: break lines.append(line) seen += len(line) if seen >= sizehint: break return lines def finish(self): self.done = True if self.has_trailers and hasattr(self.fp, 'read_trailer_lines'): self.trailers = {} try: for line in self.fp.read_trailer_lines(): if line[0] in ntob(' \t'): # It's a continuation line. v = line.strip() else: try: k, v = line.split(ntob(':'), 1) except ValueError: raise ValueError('Illegal header line.') k = k.strip().title() v = v.strip() if k in comma_separated_headers: existing = self.trailers.get(envname) if existing: v = ntob(', ').join((existing, v)) self.trailers[k] = v except Exception: e = sys.exc_info()[1] if e.__class__.__name__ == 'MaxSizeExceeded': # Post data is too big raise cherrypy.HTTPError( 413, 'Maximum request length: %r' % e.args[1]) else: raise class RequestBody(Entity): """The entity of the HTTP request.""" bufsize = 8 * 1024 """The buffer size used when reading the socket.""" # Don't parse the request body at all if the client didn't provide # a Content-Type header. See # https://github.com/cherrypy/cherrypy/issues/790 default_content_type = '' """This defines a default ``Content-Type`` to use if no Content-Type header is given. The empty string is used for RequestBody, which results in the request body not being read or parsed at all. This is by design; a missing ``Content-Type`` header in the HTTP request entity is an error at best, and a security hole at worst. For multipart parts, however, the MIME spec declares that a part with no Content-Type defaults to "text/plain" (see :class:`Part`). """ maxbytes = None """Raise ``MaxSizeExceeded`` if more bytes than this are read from the socket. """ def __init__(self, fp, headers, params=None, request_params=None): Entity.__init__(self, fp, headers, params) # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1 # When no explicit charset parameter is provided by the # sender, media subtypes of the "text" type are defined # to have a default charset value of "ISO-8859-1" when # received via HTTP. if self.content_type.value.startswith('text/'): for c in ('ISO-8859-1', 'iso-8859-1', 'Latin-1', 'latin-1'): if c in self.attempt_charsets: break else: self.attempt_charsets.append('ISO-8859-1') # Temporary fix while deprecating passing .parts as .params. self.processors['multipart'] = _old_process_multipart if request_params is None: request_params = {} self.request_params = request_params def process(self): """Process the request entity based on its Content-Type.""" # "The presence of a message-body in a request is signaled by the # inclusion of a Content-Length or Transfer-Encoding header field in # the request's message-headers." # It is possible to send a POST request with no body, for example; # however, app developers are responsible in that case to set # cherrypy.request.process_body to False so this method isn't called. h = cherrypy.serving.request.headers if 'Content-Length' not in h and 'Transfer-Encoding' not in h: raise cherrypy.HTTPError(411) self.fp = SizedReader(self.fp, self.length, self.maxbytes, bufsize=self.bufsize, has_trailers='Trailer' in h) super(RequestBody, self).process() # Body params should also be a part of the request_params # add them in here. request_params = self.request_params for key, value in self.params.items(): # Python 2 only: keyword arguments must be byte strings (type # 'str'). if sys.version_info < (3, 0): if isinstance(key, unicode): key = key.encode('ISO-8859-1') if key in request_params: if not isinstance(request_params[key], list): request_params[key] = [request_params[key]] request_params[key].append(value) else: request_params[key] = value SABnzbd-2.3.2/cherrypy/_cprequest.py0000644000000000000000000011026513217005257015527 0ustar 00000000000000import sys import time import warnings import six import cherrypy from cherrypy._cpcompat import text_or_bytes, copykeys, ntob from cherrypy._cpcompat import SimpleCookie, CookieError from cherrypy import _cpreqbody, _cpconfig from cherrypy._cperror import format_exc, bare_error from cherrypy.lib import httputil, file_generator class Hook(object): """A callback and its metadata: failsafe, priority, and kwargs.""" callback = None """ The bare callable that this Hook object is wrapping, which will be called when the Hook is called.""" failsafe = False """ If True, the callback is guaranteed to run even if other callbacks from the same call point raise exceptions.""" priority = 50 """ Defines the order of execution for a list of Hooks. Priority numbers should be limited to the closed interval [0, 100], but values outside this range are acceptable, as are fractional values.""" kwargs = {} """ A set of keyword arguments that will be passed to the callable on each call.""" def __init__(self, callback, failsafe=None, priority=None, **kwargs): self.callback = callback if failsafe is None: failsafe = getattr(callback, 'failsafe', False) self.failsafe = failsafe if priority is None: priority = getattr(callback, 'priority', 50) self.priority = priority self.kwargs = kwargs def __lt__(self, other): # Python 3 return self.priority < other.priority def __cmp__(self, other): # Python 2 return cmp(self.priority, other.priority) def __call__(self): """Run self.callback(**self.kwargs).""" return self.callback(**self.kwargs) def __repr__(self): cls = self.__class__ return ('%s.%s(callback=%r, failsafe=%r, priority=%r, %s)' % (cls.__module__, cls.__name__, self.callback, self.failsafe, self.priority, ', '.join(['%s=%r' % (k, v) for k, v in self.kwargs.items()]))) class HookMap(dict): """A map of call points to lists of callbacks (Hook objects).""" def __new__(cls, points=None): d = dict.__new__(cls) for p in points or []: d[p] = [] return d def __init__(self, *a, **kw): pass def attach(self, point, callback, failsafe=None, priority=None, **kwargs): """Append a new Hook made from the supplied arguments.""" self[point].append(Hook(callback, failsafe, priority, **kwargs)) def run(self, point): """Execute all registered Hooks (callbacks) for the given point.""" exc = None hooks = self[point] hooks.sort() for hook in hooks: # Some hooks are guaranteed to run even if others at # the same hookpoint fail. We will still log the failure, # but proceed on to the next hook. The only way # to stop all processing from one of these hooks is # to raise SystemExit and stop the whole server. if exc is None or hook.failsafe: try: hook() except (KeyboardInterrupt, SystemExit): raise except (cherrypy.HTTPError, cherrypy.HTTPRedirect, cherrypy.InternalRedirect): exc = sys.exc_info()[1] except: exc = sys.exc_info()[1] cherrypy.log(traceback=True, severity=40) if exc: raise exc def __copy__(self): newmap = self.__class__() # We can't just use 'update' because we want copies of the # mutable values (each is a list) as well. for k, v in self.items(): newmap[k] = v[:] return newmap copy = __copy__ def __repr__(self): cls = self.__class__ return '%s.%s(points=%r)' % ( cls.__module__, cls.__name__, copykeys(self) ) # Config namespace handlers def hooks_namespace(k, v): """Attach bare hooks declared in config.""" # Use split again to allow multiple hooks for a single # hookpoint per path (e.g. "hooks.before_handler.1"). # Little-known fact you only get from reading source ;) hookpoint = k.split('.', 1)[0] if isinstance(v, text_or_bytes): v = cherrypy.lib.attributes(v) if not isinstance(v, Hook): v = Hook(v) cherrypy.serving.request.hooks[hookpoint].append(v) def request_namespace(k, v): """Attach request attributes declared in config.""" # Provides config entries to set request.body attrs (like # attempt_charsets). if k[:5] == 'body.': setattr(cherrypy.serving.request.body, k[5:], v) else: setattr(cherrypy.serving.request, k, v) def response_namespace(k, v): """Attach response attributes declared in config.""" # Provides config entries to set default response headers # http://cherrypy.org/ticket/889 if k[:8] == 'headers.': cherrypy.serving.response.headers[k.split('.', 1)[1]] = v else: setattr(cherrypy.serving.response, k, v) def error_page_namespace(k, v): """Attach error pages declared in config.""" if k != 'default': k = int(k) cherrypy.serving.request.error_page[k] = v hookpoints = ['on_start_resource', 'before_request_body', 'before_handler', 'before_finalize', 'on_end_resource', 'on_end_request', 'before_error_response', 'after_error_response'] class Request(object): """An HTTP request. This object represents the metadata of an HTTP request message; that is, it contains attributes which describe the environment in which the request URL, headers, and body were sent (if you want tools to interpret the headers and body, those are elsewhere, mostly in Tools). This 'metadata' consists of socket data, transport characteristics, and the Request-Line. This object also contains data regarding the configuration in effect for the given URL, and the execution plan for generating a response. """ prev = None """ The previous Request object (if any). This should be None unless we are processing an InternalRedirect.""" # Conversation/connection attributes local = httputil.Host('127.0.0.1', 80) 'An httputil.Host(ip, port, hostname) object for the server socket.' remote = httputil.Host('127.0.0.1', 1111) 'An httputil.Host(ip, port, hostname) object for the client socket.' scheme = 'http' """ The protocol used between client and server. In most cases, this will be either 'http' or 'https'.""" server_protocol = 'HTTP/1.1' """ The HTTP version for which the HTTP server is at least conditionally compliant.""" base = '' """The (scheme://host) portion of the requested URL. In some cases (e.g. when proxying via mod_rewrite), this may contain path segments which cherrypy.url uses when constructing url's, but which otherwise are ignored by CherryPy. Regardless, this value MUST NOT end in a slash.""" # Request-Line attributes request_line = '' """ The complete Request-Line received from the client. This is a single string consisting of the request method, URI, and protocol version (joined by spaces). Any final CRLF is removed.""" method = 'GET' """ Indicates the HTTP method to be performed on the resource identified by the Request-URI. Common methods include GET, HEAD, POST, PUT, and DELETE. CherryPy allows any extension method; however, various HTTP servers and gateways may restrict the set of allowable methods. CherryPy applications SHOULD restrict the set (on a per-URI basis).""" query_string = '' """ The query component of the Request-URI, a string of information to be interpreted by the resource. The query portion of a URI follows the path component, and is separated by a '?'. For example, the URI 'http://www.cherrypy.org/wiki?a=3&b=4' has the query component, 'a=3&b=4'.""" query_string_encoding = 'utf8' """ The encoding expected for query string arguments after % HEX HEX decoding). If a query string is provided that cannot be decoded with this encoding, 404 is raised (since technically it's a different URI). If you want arbitrary encodings to not error, set this to 'Latin-1'; you can then encode back to bytes and re-decode to whatever encoding you like later. """ protocol = (1, 1) """The HTTP protocol version corresponding to the set of features which should be allowed in the response. If BOTH the client's request message AND the server's level of HTTP compliance is HTTP/1.1, this attribute will be the tuple (1, 1). If either is 1.0, this attribute will be the tuple (1, 0). Lower HTTP protocol versions are not explicitly supported.""" params = {} """ A dict which combines query string (GET) and request entity (POST) variables. This is populated in two stages: GET params are added before the 'on_start_resource' hook, and POST params are added between the 'before_request_body' and 'before_handler' hooks.""" # Message attributes header_list = [] """ A list of the HTTP request headers as (name, value) tuples. In general, you should use request.headers (a dict) instead.""" headers = httputil.HeaderMap() """ A dict-like object containing the request headers. Keys are header names (in Title-Case format); however, you may get and set them in a case-insensitive manner. That is, headers['Content-Type'] and headers['content-type'] refer to the same value. Values are header values (decoded according to :rfc:`2047` if necessary). See also: httputil.HeaderMap, httputil.HeaderElement.""" cookie = SimpleCookie() """See help(Cookie).""" rfile = None """ If the request included an entity (body), it will be available as a stream in this attribute. However, the rfile will normally be read for you between the 'before_request_body' hook and the 'before_handler' hook, and the resulting string is placed into either request.params or the request.body attribute. You may disable the automatic consumption of the rfile by setting request.process_request_body to False, either in config for the desired path, or in an 'on_start_resource' or 'before_request_body' hook. WARNING: In almost every case, you should not attempt to read from the rfile stream after CherryPy's automatic mechanism has read it. If you turn off the automatic parsing of rfile, you should read exactly the number of bytes specified in request.headers['Content-Length']. Ignoring either of these warnings may result in a hung request thread or in corruption of the next (pipelined) request. """ process_request_body = True """ If True, the rfile (if any) is automatically read and parsed, and the result placed into request.params or request.body.""" methods_with_bodies = ('POST', 'PUT') """ A sequence of HTTP methods for which CherryPy will automatically attempt to read a body from the rfile. If you are going to change this property, modify it on the configuration (recommended) or on the "hook point" `on_start_resource`. """ body = None """ If the request Content-Type is 'application/x-www-form-urlencoded' or multipart, this will be None. Otherwise, this will be an instance of :class:`RequestBody` (which you can .read()); this value is set between the 'before_request_body' and 'before_handler' hooks (assuming that process_request_body is True).""" # Dispatch attributes dispatch = cherrypy.dispatch.Dispatcher() """ The object which looks up the 'page handler' callable and collects config for the current request based on the path_info, other request attributes, and the application architecture. The core calls the dispatcher as early as possible, passing it a 'path_info' argument. The default dispatcher discovers the page handler by matching path_info to a hierarchical arrangement of objects, starting at request.app.root. See help(cherrypy.dispatch) for more information.""" script_name = '' """ The 'mount point' of the application which is handling this request. This attribute MUST NOT end in a slash. If the script_name refers to the root of the URI, it MUST be an empty string (not "/"). """ path_info = '/' """ The 'relative path' portion of the Request-URI. This is relative to the script_name ('mount point') of the application which is handling this request.""" login = None """ When authentication is used during the request processing this is set to 'False' if it failed and to the 'username' value if it succeeded. The default 'None' implies that no authentication happened.""" # Note that cherrypy.url uses "if request.app:" to determine whether # the call is during a real HTTP request or not. So leave this None. app = None """The cherrypy.Application object which is handling this request.""" handler = None """ The function, method, or other callable which CherryPy will call to produce the response. The discovery of the handler and the arguments it will receive are determined by the request.dispatch object. By default, the handler is discovered by walking a tree of objects starting at request.app.root, and is then passed all HTTP params (from the query string and POST body) as keyword arguments.""" toolmaps = {} """ A nested dict of all Toolboxes and Tools in effect for this request, of the form: {Toolbox.namespace: {Tool.name: config dict}}.""" config = None """ A flat dict of all configuration entries which apply to the current request. These entries are collected from global config, application config (based on request.path_info), and from handler config (exactly how is governed by the request.dispatch object in effect for this request; by default, handler config can be attached anywhere in the tree between request.app.root and the final handler, and inherits downward).""" is_index = None """ This will be True if the current request is mapped to an 'index' resource handler (also, a 'default' handler if path_info ends with a slash). The value may be used to automatically redirect the user-agent to a 'more canonical' URL which either adds or removes the trailing slash. See cherrypy.tools.trailing_slash.""" hooks = HookMap(hookpoints) """ A HookMap (dict-like object) of the form: {hookpoint: [hook, ...]}. Each key is a str naming the hook point, and each value is a list of hooks which will be called at that hook point during this request. The list of hooks is generally populated as early as possible (mostly from Tools specified in config), but may be extended at any time. See also: _cprequest.Hook, _cprequest.HookMap, and cherrypy.tools.""" error_response = cherrypy.HTTPError(500).set_response """ The no-arg callable which will handle unexpected, untrapped errors during request processing. This is not used for expected exceptions (like NotFound, HTTPError, or HTTPRedirect) which are raised in response to expected conditions (those should be customized either via request.error_page or by overriding HTTPError.set_response). By default, error_response uses HTTPError(500) to return a generic error response to the user-agent.""" error_page = {} """ A dict of {error code: response filename or callable} pairs. The error code must be an int representing a given HTTP error code, or the string 'default', which will be used if no matching entry is found for a given numeric code. If a filename is provided, the file should contain a Python string- formatting template, and can expect by default to receive format values with the mapping keys %(status)s, %(message)s, %(traceback)s, and %(version)s. The set of format mappings can be extended by overriding HTTPError.set_response. If a callable is provided, it will be called by default with keyword arguments 'status', 'message', 'traceback', and 'version', as for a string-formatting template. The callable must return a string or iterable of strings which will be set to response.body. It may also override headers or perform any other processing. If no entry is given for an error code, and no 'default' entry exists, a default template will be used. """ show_tracebacks = True """ If True, unexpected errors encountered during request processing will include a traceback in the response body.""" show_mismatched_params = True """ If True, mismatched parameters encountered during PageHandler invocation processing will be included in the response body.""" throws = (KeyboardInterrupt, SystemExit, cherrypy.InternalRedirect) """The sequence of exceptions which Request.run does not trap.""" throw_errors = False """ If True, Request.run will not trap any errors (except HTTPRedirect and HTTPError, which are more properly called 'exceptions', not errors).""" closed = False """True once the close method has been called, False otherwise.""" stage = None """ A string containing the stage reached in the request-handling process. This is useful when debugging a live server with hung requests.""" namespaces = _cpconfig.NamespaceSet( **{'hooks': hooks_namespace, 'request': request_namespace, 'response': response_namespace, 'error_page': error_page_namespace, 'tools': cherrypy.tools, }) def __init__(self, local_host, remote_host, scheme='http', server_protocol='HTTP/1.1'): """Populate a new Request object. local_host should be an httputil.Host object with the server info. remote_host should be an httputil.Host object with the client info. scheme should be a string, either "http" or "https". """ self.local = local_host self.remote = remote_host self.scheme = scheme self.server_protocol = server_protocol self.closed = False # Put a *copy* of the class error_page into self. self.error_page = self.error_page.copy() # Put a *copy* of the class namespaces into self. self.namespaces = self.namespaces.copy() self.stage = None def close(self): """Run cleanup code. (Core)""" if not self.closed: self.closed = True self.stage = 'on_end_request' self.hooks.run('on_end_request') self.stage = 'close' def run(self, method, path, query_string, req_protocol, headers, rfile): r"""Process the Request. (Core) method, path, query_string, and req_protocol should be pulled directly from the Request-Line (e.g. "GET /path?key=val HTTP/1.0"). path This should be %XX-unquoted, but query_string should not be. When using Python 2, they both MUST be byte strings, not unicode strings. When using Python 3, they both MUST be unicode strings, not byte strings, and preferably not bytes \x00-\xFF disguised as unicode. headers A list of (name, value) tuples. rfile A file-like object containing the HTTP request entity. When run() is done, the returned object should have 3 attributes: * status, e.g. "200 OK" * header_list, a list of (name, value) tuples * body, an iterable yielding strings Consumer code (HTTP servers) should then access these response attributes to build the outbound stream. """ response = cherrypy.serving.response self.stage = 'run' try: self.error_response = cherrypy.HTTPError(500).set_response self.method = method path = path or '/' self.query_string = query_string or '' self.params = {} # Compare request and server HTTP protocol versions, in case our # server does not support the requested protocol. Limit our output # to min(req, server). We want the following output: # request server actual written supported response # protocol protocol response protocol feature set # a 1.0 1.0 1.0 1.0 # b 1.0 1.1 1.1 1.0 # c 1.1 1.0 1.0 1.0 # d 1.1 1.1 1.1 1.1 # Notice that, in (b), the response will be "HTTP/1.1" even though # the client only understands 1.0. RFC 2616 10.5.6 says we should # only return 505 if the _major_ version is different. rp = int(req_protocol[5]), int(req_protocol[7]) sp = int(self.server_protocol[5]), int(self.server_protocol[7]) self.protocol = min(rp, sp) response.headers.protocol = self.protocol # Rebuild first line of the request (e.g. "GET /path HTTP/1.0"). url = path if query_string: url += '?' + query_string self.request_line = '%s %s %s' % (method, url, req_protocol) self.header_list = list(headers) self.headers = httputil.HeaderMap() self.rfile = rfile self.body = None self.cookie = SimpleCookie() self.handler = None # path_info should be the path from the # app root (script_name) to the handler. self.script_name = self.app.script_name self.path_info = pi = path[len(self.script_name):] self.stage = 'respond' self.respond(pi) except self.throws: raise except: if self.throw_errors: raise else: # Failure in setup, error handler or finalize. Bypass them. # Can't use handle_error because we may not have hooks yet. cherrypy.log(traceback=True, severity=40) if self.show_tracebacks: body = format_exc() else: body = '' r = bare_error(body) response.output_status, response.header_list, response.body = r if self.method == 'HEAD': # HEAD requests MUST NOT return a message-body in the response. response.body = [] try: cherrypy.log.access() except: cherrypy.log.error(traceback=True) if response.timed_out: raise cherrypy.TimeoutError() return response # Uncomment for stage debugging # stage = property(lambda self: self._stage, lambda self, v: print(v)) def respond(self, path_info): """Generate a response for the resource at self.path_info. (Core)""" response = cherrypy.serving.response try: try: try: if self.app is None: raise cherrypy.NotFound() # Get the 'Host' header, so we can HTTPRedirect properly. self.stage = 'process_headers' self.process_headers() # Make a copy of the class hooks self.hooks = self.__class__.hooks.copy() self.toolmaps = {} self.stage = 'get_resource' self.get_resource(path_info) self.body = _cpreqbody.RequestBody( self.rfile, self.headers, request_params=self.params) self.namespaces(self.config) self.stage = 'on_start_resource' self.hooks.run('on_start_resource') # Parse the querystring self.stage = 'process_query_string' self.process_query_string() # Process the body if self.process_request_body: if self.method not in self.methods_with_bodies: self.process_request_body = False self.stage = 'before_request_body' self.hooks.run('before_request_body') if self.process_request_body: self.body.process() # Run the handler self.stage = 'before_handler' self.hooks.run('before_handler') if self.handler: self.stage = 'handler' response.body = self.handler() # Finalize self.stage = 'before_finalize' self.hooks.run('before_finalize') response.finalize() except (cherrypy.HTTPRedirect, cherrypy.HTTPError): inst = sys.exc_info()[1] inst.set_response() self.stage = 'before_finalize (HTTPError)' self.hooks.run('before_finalize') response.finalize() finally: self.stage = 'on_end_resource' self.hooks.run('on_end_resource') except self.throws: raise except: if self.throw_errors: raise self.handle_error() def process_query_string(self): """Parse the query string into Python structures. (Core)""" try: p = httputil.parse_query_string( self.query_string, encoding=self.query_string_encoding) except UnicodeDecodeError: raise cherrypy.HTTPError( 404, 'The given query string could not be processed. Query ' 'strings for this resource must be encoded with %r.' % self.query_string_encoding) # Python 2 only: keyword arguments must be byte strings (type 'str'). if six.PY2: for key, value in p.items(): if isinstance(key, six.text_type): del p[key] p[key.encode(self.query_string_encoding)] = value self.params.update(p) def process_headers(self): """Parse HTTP header data into Python structures. (Core)""" # Process the headers into self.headers headers = self.headers for name, value in self.header_list: # Call title() now (and use dict.__method__(headers)) # so title doesn't have to be called twice. name = name.title() value = value.strip() # Warning: if there is more than one header entry for cookies # (AFAIK, only Konqueror does that), only the last one will # remain in headers (but they will be correctly stored in # request.cookie). if '=?' in value: dict.__setitem__(headers, name, httputil.decode_TEXT(value)) else: dict.__setitem__(headers, name, value) # Handle cookies differently because on Konqueror, multiple # cookies come on different lines with the same key if name == 'Cookie': try: self.cookie.load(value) except CookieError: msg = 'Illegal cookie name %s' % value.split('=')[0] raise cherrypy.HTTPError(400, msg) if not dict.__contains__(headers, 'Host'): # All Internet-based HTTP/1.1 servers MUST respond with a 400 # (Bad Request) status code to any HTTP/1.1 request message # which lacks a Host header field. if self.protocol >= (1, 1): msg = "HTTP/1.1 requires a 'Host' request header." raise cherrypy.HTTPError(400, msg) host = dict.get(headers, 'Host') if not host: host = self.local.name or self.local.ip self.base = '%s://%s' % (self.scheme, host) def get_resource(self, path): """Call a dispatcher (which sets self.handler and .config). (Core)""" # First, see if there is a custom dispatch at this URI. Custom # dispatchers can only be specified in app.config, not in _cp_config # (since custom dispatchers may not even have an app.root). dispatch = self.app.find_config( path, 'request.dispatch', self.dispatch) # dispatch() should set self.handler and self.config dispatch(path) def handle_error(self): """Handle the last unanticipated exception. (Core)""" try: self.hooks.run('before_error_response') if self.error_response: self.error_response() self.hooks.run('after_error_response') cherrypy.serving.response.finalize() except cherrypy.HTTPRedirect: inst = sys.exc_info()[1] inst.set_response() cherrypy.serving.response.finalize() # ------------------------- Properties ------------------------- # def _get_body_params(self): warnings.warn( 'body_params is deprecated in CherryPy 3.2, will be removed in ' 'CherryPy 3.3.', DeprecationWarning ) return self.body.params body_params = property(_get_body_params, doc=""" If the request Content-Type is 'application/x-www-form-urlencoded' or multipart, this will be a dict of the params pulled from the entity body; that is, it will be the portion of request.params that come from the message body (sometimes called "POST params", although they can be sent with various HTTP method verbs). This value is set between the 'before_request_body' and 'before_handler' hooks (assuming that process_request_body is True). Deprecated in 3.2, will be removed for 3.3 in favor of :attr:`request.body.params`.""") class ResponseBody(object): """The body of the HTTP response (the response entity).""" if six.PY3: unicode_err = ('Page handlers MUST return bytes. Use tools.encode ' 'if you wish to return unicode.') def __get__(self, obj, objclass=None): if obj is None: # When calling on the class instead of an instance... return self else: return obj._body def __set__(self, obj, value): # Convert the given value to an iterable object. if six.PY3 and isinstance(value, str): raise ValueError(self.unicode_err) if isinstance(value, text_or_bytes): # strings get wrapped in a list because iterating over a single # item list is much faster than iterating over every character # in a long string. if value: value = [value] else: # [''] doesn't evaluate to False, so replace it with []. value = [] elif six.PY3 and isinstance(value, list): # every item in a list must be bytes... for i, item in enumerate(value): if isinstance(item, str): raise ValueError(self.unicode_err) # Don't use isinstance here; io.IOBase which has an ABC takes # 1000 times as long as, say, isinstance(value, str) elif hasattr(value, 'read'): value = file_generator(value) elif value is None: value = [] obj._body = value class Response(object): """An HTTP Response, including status, headers, and body.""" status = '' """The HTTP Status-Code and Reason-Phrase.""" header_list = [] """ A list of the HTTP response headers as (name, value) tuples. In general, you should use response.headers (a dict) instead. This attribute is generated from response.headers and is not valid until after the finalize phase.""" headers = httputil.HeaderMap() """ A dict-like object containing the response headers. Keys are header names (in Title-Case format); however, you may get and set them in a case-insensitive manner. That is, headers['Content-Type'] and headers['content-type'] refer to the same value. Values are header values (decoded according to :rfc:`2047` if necessary). .. seealso:: classes :class:`HeaderMap`, :class:`HeaderElement` """ cookie = SimpleCookie() """See help(Cookie).""" body = ResponseBody() """The body (entity) of the HTTP response.""" time = None """The value of time.time() when created. Use in HTTP dates.""" timeout = 300 """Seconds after which the response will be aborted.""" timed_out = False """ Flag to indicate the response should be aborted, because it has exceeded its timeout.""" stream = False """If False, buffer the response body.""" def __init__(self): self.status = None self.header_list = None self._body = [] self.time = time.time() self.headers = httputil.HeaderMap() # Since we know all our keys are titled strings, we can # bypass HeaderMap.update and get a big speed boost. dict.update(self.headers, { 'Content-Type': 'text/html', 'Server': 'CherryPy/' + cherrypy.__version__, 'Date': httputil.HTTPDate(self.time), }) self.cookie = SimpleCookie() def collapse_body(self): """Collapse self.body to a single string; replace it and return it.""" if isinstance(self.body, text_or_bytes): return self.body newbody = [] for chunk in self.body: if six.PY3 and not isinstance(chunk, bytes): raise TypeError("Chunk %s is not of type 'bytes'." % repr(chunk)) newbody.append(chunk) newbody = ntob('').join(newbody) self.body = newbody return newbody def finalize(self): """Transform headers (and cookies) into self.header_list. (Core)""" try: code, reason, _ = httputil.valid_status(self.status) except ValueError: raise cherrypy.HTTPError(500, sys.exc_info()[1].args[0]) headers = self.headers self.status = '%s %s' % (code, reason) self.output_status = ntob(str(code), 'ascii') + \ ntob(' ') + headers.encode(reason) if self.stream: # The upshot: wsgiserver will chunk the response if # you pop Content-Length (or set it explicitly to None). # Note that lib.static sets C-L to the file's st_size. if dict.get(headers, 'Content-Length') is None: dict.pop(headers, 'Content-Length', None) elif code < 200 or code in (204, 205, 304): # "All 1xx (informational), 204 (no content), # and 304 (not modified) responses MUST NOT # include a message-body." dict.pop(headers, 'Content-Length', None) self.body = ntob('') else: # Responses which are not streamed should have a Content-Length, # but allow user code to set Content-Length if desired. if dict.get(headers, 'Content-Length') is None: content = self.collapse_body() dict.__setitem__(headers, 'Content-Length', len(content)) # Transform our header dict into a list of tuples. self.header_list = h = headers.output() cookie = self.cookie.output() if cookie: for line in cookie.split('\r\n'): name, value = line.split(': ', 1) if isinstance(name, six.text_type): name = name.encode('ISO-8859-1') if isinstance(value, six.text_type): value = headers.encode(value) h.append((name, value)) def check_timeout(self): """If now > self.time + self.timeout, set self.timed_out. This purposefully sets a flag, rather than raising an error, so that a monitor thread can interrupt the Response thread. """ if time.time() > self.time + self.timeout: self.timed_out = True SABnzbd-2.3.2/cherrypy/_cpserver.py0000644000000000000000000002012513217005257015340 0ustar 00000000000000"""Manage HTTP servers with CherryPy.""" import six import cherrypy from cherrypy.lib.reprconf import attributes from cherrypy._cpcompat import text_or_bytes # We import * because we want to export check_port # et al as attributes of this module. from cherrypy.process.servers import * class Server(ServerAdapter): """An adapter for an HTTP server. You can set attributes (like socket_host and socket_port) on *this* object (which is probably cherrypy.server), and call quickstart. For example:: cherrypy.server.socket_port = 80 cherrypy.quickstart() """ socket_port = 8080 """The TCP port on which to listen for connections.""" _socket_host = '127.0.0.1' def _get_socket_host(self): return self._socket_host def _set_socket_host(self, value): if value == '': raise ValueError("The empty string ('') is not an allowed value. " "Use '0.0.0.0' instead to listen on all active " 'interfaces (INADDR_ANY).') self._socket_host = value socket_host = property( _get_socket_host, _set_socket_host, doc="""The hostname or IP address on which to listen for connections. Host values may be any IPv4 or IPv6 address, or any valid hostname. The string 'localhost' is a synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6). The string '0.0.0.0' is a special IPv4 entry meaning "any active interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for IPv6. The empty string or None are not allowed.""") socket_file = None """If given, the name of the UNIX socket to use instead of TCP/IP. When this option is not None, the `socket_host` and `socket_port` options are ignored.""" socket_queue_size = 5 """The 'backlog' argument to socket.listen(); specifies the maximum number of queued connections (default 5).""" socket_timeout = 10 """The timeout in seconds for accepted connections (default 10).""" accepted_queue_size = -1 """The maximum number of requests which will be queued up before the server refuses to accept it (default -1, meaning no limit).""" accepted_queue_timeout = 10 """The timeout in seconds for attempting to add a request to the queue when the queue is full (default 10).""" shutdown_timeout = 5 """The time to wait for HTTP worker threads to clean up.""" protocol_version = 'HTTP/1.1' """The version string to write in the Status-Line of all HTTP responses, for example, "HTTP/1.1" (the default). Depending on the HTTP server used, this should also limit the supported features used in the response.""" thread_pool = 10 """The number of worker threads to start up in the pool.""" thread_pool_max = -1 """The maximum size of the worker-thread pool. Use -1 to indicate no limit. """ max_request_header_size = 500 * 1024 """The maximum number of bytes allowable in the request headers. If exceeded, the HTTP server should return "413 Request Entity Too Large". """ max_request_body_size = 100 * 1024 * 1024 """The maximum number of bytes allowable in the request body. If exceeded, the HTTP server should return "413 Request Entity Too Large".""" instance = None """If not None, this should be an HTTP server instance (such as CPWSGIServer) which cherrypy.server will control. Use this when you need more control over object instantiation than is available in the various configuration options.""" ssl_context = None """When using PyOpenSSL, an instance of SSL.Context.""" ssl_certificate = None """The filename of the SSL certificate to use.""" ssl_certificate_chain = None """When using PyOpenSSL, the certificate chain to pass to Context.load_verify_locations.""" ssl_private_key = None """The filename of the private key to use with SSL.""" if six.PY3: ssl_module = 'builtin' """The name of a registered SSL adaptation module to use with the builtin WSGI server. Builtin options are: 'builtin' (to use the SSL library built into recent versions of Python). You may also register your own classes in the wsgiserver.ssl_adapters dict.""" else: ssl_module = 'pyopenssl' """The name of a registered SSL adaptation module to use with the builtin WSGI server. Builtin options are 'builtin' (to use the SSL library built into recent versions of Python) and 'pyopenssl' (to use the PyOpenSSL project, which you must install separately). You may also register your own classes in the wsgiserver.ssl_adapters dict.""" statistics = False """Turns statistics-gathering on or off for aware HTTP servers.""" nodelay = True """If True (the default since 3.1), sets the TCP_NODELAY socket option.""" wsgi_version = (1, 0) """The WSGI version tuple to use with the builtin WSGI server. The provided options are (1, 0) [which includes support for PEP 3333, which declares it covers WSGI version 1.0.1 but still mandates the wsgi.version (1, 0)] and ('u', 0), an experimental unicode version. You may create and register your own experimental versions of the WSGI protocol by adding custom classes to the wsgiserver.wsgi_gateways dict.""" def __init__(self): self.bus = cherrypy.engine self.httpserver = None self.interrupt = None self.running = False def httpserver_from_self(self, httpserver=None): """Return a (httpserver, bind_addr) pair based on self attributes.""" if httpserver is None: httpserver = self.instance if httpserver is None: from cherrypy import _cpwsgi_server httpserver = _cpwsgi_server.CPWSGIServer(self) if isinstance(httpserver, text_or_bytes): # Is anyone using this? Can I add an arg? httpserver = attributes(httpserver)(self) return httpserver, self.bind_addr def start(self): """Start the HTTP server.""" if not self.httpserver: self.httpserver, self.bind_addr = self.httpserver_from_self() ServerAdapter.start(self) start.priority = 75 def _get_bind_addr(self): if self.socket_file: return self.socket_file if self.socket_host is None and self.socket_port is None: return None return (self.socket_host, self.socket_port) def _set_bind_addr(self, value): if value is None: self.socket_file = None self.socket_host = None self.socket_port = None elif isinstance(value, text_or_bytes): self.socket_file = value self.socket_host = None self.socket_port = None else: try: self.socket_host, self.socket_port = value self.socket_file = None except ValueError: raise ValueError('bind_addr must be a (host, port) tuple ' '(for TCP sockets) or a string (for Unix ' 'domain sockets), not %r' % value) bind_addr = property( _get_bind_addr, _set_bind_addr, doc='A (host, port) tuple for TCP sockets or ' 'a str for Unix domain sockets.') def base(self): """Return the base (scheme://host[:port] or sock file) for this server. """ if self.socket_file: return self.socket_file host = self.socket_host if host in ('0.0.0.0', '::'): # 0.0.0.0 is INADDR_ANY and :: is IN6ADDR_ANY. # Look up the host name, which should be the # safest thing to spit out in a URL. import socket host = socket.gethostname() port = self.socket_port if self.ssl_certificate: scheme = 'https' if port != 443: host += ':%s' % port else: scheme = 'http' if port != 80: host += ':%s' % port return '%s://%s' % (scheme, host) SABnzbd-2.3.2/cherrypy/_cptools.py0000644000000000000000000004574213217005257015206 0ustar 00000000000000"""CherryPy tools. A "tool" is any helper, adapted to CP. Tools are usually designed to be used in a variety of ways (although some may only offer one if they choose): Library calls All tools are callables that can be used wherever needed. The arguments are straightforward and should be detailed within the docstring. Function decorators All tools, when called, may be used as decorators which configure individual CherryPy page handlers (methods on the CherryPy tree). That is, "@tools.anytool()" should "turn on" the tool via the decorated function's _cp_config attribute. CherryPy config If a tool exposes a "_setup" callable, it will be called once per Request (if the feature is "turned on" via config). Tools may be implemented as any object with a namespace. The builtins are generally either modules or instances of the tools.Tool class. """ import sys import warnings import cherrypy from cherrypy._helper import expose from cherrypy.lib import cptools, encoding, auth, static, jsontools from cherrypy.lib import sessions as _sessions, xmlrpcutil as _xmlrpc from cherrypy.lib import caching as _caching from cherrypy.lib import auth_basic, auth_digest def _getargs(func): """Return the names of all static arguments to the given function.""" # Use this instead of importing inspect for less mem overhead. import types if sys.version_info >= (3, 0): if isinstance(func, types.MethodType): func = func.__func__ co = func.__code__ else: if isinstance(func, types.MethodType): func = func.im_func co = func.func_code return co.co_varnames[:co.co_argcount] _attr_error = ( 'CherryPy Tools cannot be turned on directly. Instead, turn them ' 'on via config, or use them as decorators on your page handlers.' ) class Tool(object): """A registered function for use with CherryPy request-processing hooks. help(tool.callable) should give you more information about this Tool. """ namespace = 'tools' def __init__(self, point, callable, name=None, priority=50): self._point = point self.callable = callable self._name = name self._priority = priority self.__doc__ = self.callable.__doc__ self._setargs() def _get_on(self): raise AttributeError(_attr_error) def _set_on(self, value): raise AttributeError(_attr_error) on = property(_get_on, _set_on) def _setargs(self): """Copy func parameter names to obj attributes.""" try: for arg in _getargs(self.callable): setattr(self, arg, None) except (TypeError, AttributeError): if hasattr(self.callable, '__call__'): for arg in _getargs(self.callable.__call__): setattr(self, arg, None) # IronPython 1.0 raises NotImplementedError because # inspect.getargspec tries to access Python bytecode # in co_code attribute. except NotImplementedError: pass # IronPython 1B1 may raise IndexError in some cases, # but if we trap it here it doesn't prevent CP from working. except IndexError: pass def _merged_args(self, d=None): """Return a dict of configuration entries for this Tool.""" if d: conf = d.copy() else: conf = {} tm = cherrypy.serving.request.toolmaps[self.namespace] if self._name in tm: conf.update(tm[self._name]) if 'on' in conf: del conf['on'] return conf def __call__(self, *args, **kwargs): """Compile-time decorator (turn on the tool in config). For example:: @expose @tools.proxy() def whats_my_base(self): return cherrypy.request.base """ if args: raise TypeError('The %r Tool does not accept positional ' 'arguments; you must use keyword arguments.' % self._name) def tool_decorator(f): if not hasattr(f, '_cp_config'): f._cp_config = {} subspace = self.namespace + '.' + self._name + '.' f._cp_config[subspace + 'on'] = True for k, v in kwargs.items(): f._cp_config[subspace + k] = v return f return tool_decorator def _setup(self): """Hook this tool into cherrypy.request. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. """ conf = self._merged_args() p = conf.pop('priority', None) if p is None: p = getattr(self.callable, 'priority', self._priority) cherrypy.serving.request.hooks.attach(self._point, self.callable, priority=p, **conf) class HandlerTool(Tool): """Tool which is called 'before main', that may skip normal handlers. If the tool successfully handles the request (by setting response.body), if should return True. This will cause CherryPy to skip any 'normal' page handler. If the tool did not handle the request, it should return False to tell CherryPy to continue on and call the normal page handler. If the tool is declared AS a page handler (see the 'handler' method), returning False will raise NotFound. """ def __init__(self, callable, name=None): Tool.__init__(self, 'before_handler', callable, name) def handler(self, *args, **kwargs): """Use this tool as a CherryPy page handler. For example:: class Root: nav = tools.staticdir.handler(section="/nav", dir="nav", root=absDir) """ @expose def handle_func(*a, **kw): handled = self.callable(*args, **self._merged_args(kwargs)) if not handled: raise cherrypy.NotFound() return cherrypy.serving.response.body return handle_func def _wrapper(self, **kwargs): if self.callable(**kwargs): cherrypy.serving.request.handler = None def _setup(self): """Hook this tool into cherrypy.request. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. """ conf = self._merged_args() p = conf.pop('priority', None) if p is None: p = getattr(self.callable, 'priority', self._priority) cherrypy.serving.request.hooks.attach(self._point, self._wrapper, priority=p, **conf) class HandlerWrapperTool(Tool): """Tool which wraps request.handler in a provided wrapper function. The 'newhandler' arg must be a handler wrapper function that takes a 'next_handler' argument, plus ``*args`` and ``**kwargs``. Like all page handler functions, it must return an iterable for use as cherrypy.response.body. For example, to allow your 'inner' page handlers to return dicts which then get interpolated into a template:: def interpolator(next_handler, *args, **kwargs): filename = cherrypy.request.config.get('template') cherrypy.response.template = env.get_template(filename) response_dict = next_handler(*args, **kwargs) return cherrypy.response.template.render(**response_dict) cherrypy.tools.jinja = HandlerWrapperTool(interpolator) """ def __init__(self, newhandler, point='before_handler', name=None, priority=50): self.newhandler = newhandler self._point = point self._name = name self._priority = priority def callable(self, *args, **kwargs): innerfunc = cherrypy.serving.request.handler def wrap(*args, **kwargs): return self.newhandler(innerfunc, *args, **kwargs) cherrypy.serving.request.handler = wrap class ErrorTool(Tool): """Tool which is used to replace the default request.error_response.""" def __init__(self, callable, name=None): Tool.__init__(self, None, callable, name) def _wrapper(self): self.callable(**self._merged_args()) def _setup(self): """Hook this tool into cherrypy.request. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. """ cherrypy.serving.request.error_response = self._wrapper # Builtin tools # class SessionTool(Tool): """Session Tool for CherryPy. sessions.locking When 'implicit' (the default), the session will be locked for you, just before running the page handler. When 'early', the session will be locked before reading the request body. This is off by default for safety reasons; for example, a large upload would block the session, denying an AJAX progress meter (`issue `_). When 'explicit' (or any other value), you need to call cherrypy.session.acquire_lock() yourself before using session data. """ def __init__(self): # _sessions.init must be bound after headers are read Tool.__init__(self, 'before_request_body', _sessions.init) def _lock_session(self): cherrypy.serving.session.acquire_lock() def _setup(self): """Hook this tool into cherrypy.request. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. """ hooks = cherrypy.serving.request.hooks conf = self._merged_args() p = conf.pop('priority', None) if p is None: p = getattr(self.callable, 'priority', self._priority) hooks.attach(self._point, self.callable, priority=p, **conf) locking = conf.pop('locking', 'implicit') if locking == 'implicit': hooks.attach('before_handler', self._lock_session) elif locking == 'early': # Lock before the request body (but after _sessions.init runs!) hooks.attach('before_request_body', self._lock_session, priority=60) else: # Don't lock pass hooks.attach('before_finalize', _sessions.save) hooks.attach('on_end_request', _sessions.close) def regenerate(self): """Drop the current session and make a new one (with a new id).""" sess = cherrypy.serving.session sess.regenerate() # Grab cookie-relevant tool args conf = dict([(k, v) for k, v in self._merged_args().items() if k in ('path', 'path_header', 'name', 'timeout', 'domain', 'secure')]) _sessions.set_response_cookie(**conf) class XMLRPCController(object): """A Controller (page handler collection) for XML-RPC. To use it, have your controllers subclass this base class (it will turn on the tool for you). You can also supply the following optional config entries:: tools.xmlrpc.encoding: 'utf-8' tools.xmlrpc.allow_none: 0 XML-RPC is a rather discontinuous layer over HTTP; dispatching to the appropriate handler must first be performed according to the URL, and then a second dispatch step must take place according to the RPC method specified in the request body. It also allows a superfluous "/RPC2" prefix in the URL, supplies its own handler args in the body, and requires a 200 OK "Fault" response instead of 404 when the desired method is not found. Therefore, XML-RPC cannot be implemented for CherryPy via a Tool alone. This Controller acts as the dispatch target for the first half (based on the URL); it then reads the RPC method from the request body and does its own second dispatch step based on that method. It also reads body params, and returns a Fault on error. The XMLRPCDispatcher strips any /RPC2 prefix; if you aren't using /RPC2 in your URL's, you can safely skip turning on the XMLRPCDispatcher. Otherwise, you need to use declare it in config:: request.dispatch: cherrypy.dispatch.XMLRPCDispatcher() """ # Note we're hard-coding this into the 'tools' namespace. We could do # a huge amount of work to make it relocatable, but the only reason why # would be if someone actually disabled the default_toolbox. Meh. _cp_config = {'tools.xmlrpc.on': True} @expose def default(self, *vpath, **params): rpcparams, rpcmethod = _xmlrpc.process_body() subhandler = self for attr in str(rpcmethod).split('.'): subhandler = getattr(subhandler, attr, None) if subhandler and getattr(subhandler, 'exposed', False): body = subhandler(*(vpath + rpcparams), **params) else: # https://github.com/cherrypy/cherrypy/issues/533 # if a method is not found, an xmlrpclib.Fault should be returned # raising an exception here will do that; see # cherrypy.lib.xmlrpcutil.on_error raise Exception('method "%s" is not supported' % attr) conf = cherrypy.serving.request.toolmaps['tools'].get('xmlrpc', {}) _xmlrpc.respond(body, conf.get('encoding', 'utf-8'), conf.get('allow_none', 0)) return cherrypy.serving.response.body class SessionAuthTool(HandlerTool): def _setargs(self): for name in dir(cptools.SessionAuth): if not name.startswith('__'): setattr(self, name, None) class CachingTool(Tool): """Caching Tool for CherryPy.""" def _wrapper(self, **kwargs): request = cherrypy.serving.request if _caching.get(**kwargs): request.handler = None else: if request.cacheable: # Note the devious technique here of adding hooks on the fly request.hooks.attach('before_finalize', _caching.tee_output, priority=90) _wrapper.priority = 20 def _setup(self): """Hook caching into cherrypy.request.""" conf = self._merged_args() p = conf.pop('priority', None) cherrypy.serving.request.hooks.attach('before_handler', self._wrapper, priority=p, **conf) class Toolbox(object): """A collection of Tools. This object also functions as a config namespace handler for itself. Custom toolboxes should be added to each Application's toolboxes dict. """ def __init__(self, namespace): self.namespace = namespace def __setattr__(self, name, value): # If the Tool._name is None, supply it from the attribute name. if isinstance(value, Tool): if value._name is None: value._name = name value.namespace = self.namespace object.__setattr__(self, name, value) def __enter__(self): """Populate request.toolmaps from tools specified in config.""" cherrypy.serving.request.toolmaps[self.namespace] = map = {} def populate(k, v): toolname, arg = k.split('.', 1) bucket = map.setdefault(toolname, {}) bucket[arg] = v return populate def __exit__(self, exc_type, exc_val, exc_tb): """Run tool._setup() for each tool in our toolmap.""" map = cherrypy.serving.request.toolmaps.get(self.namespace) if map: for name, settings in map.items(): if settings.get('on', False): tool = getattr(self, name) tool._setup() def register(self, point, **kwargs): """Return a decorator which registers the function at the given hook point.""" def decorator(func): setattr(self, kwargs.get('name', func.__name__), Tool(point, func, **kwargs)) return func return decorator class DeprecatedTool(Tool): _name = None warnmsg = 'This Tool is deprecated.' def __init__(self, point, warnmsg=None): self.point = point if warnmsg is not None: self.warnmsg = warnmsg def __call__(self, *args, **kwargs): warnings.warn(self.warnmsg) def tool_decorator(f): return f return tool_decorator def _setup(self): warnings.warn(self.warnmsg) default_toolbox = _d = Toolbox('tools') _d.session_auth = SessionAuthTool(cptools.session_auth) _d.allow = Tool('on_start_resource', cptools.allow) _d.proxy = Tool('before_request_body', cptools.proxy, priority=30) _d.response_headers = Tool('on_start_resource', cptools.response_headers) _d.log_tracebacks = Tool('before_error_response', cptools.log_traceback) _d.log_headers = Tool('before_error_response', cptools.log_request_headers) _d.log_hooks = Tool('on_end_request', cptools.log_hooks, priority=100) _d.err_redirect = ErrorTool(cptools.redirect) _d.etags = Tool('before_finalize', cptools.validate_etags, priority=75) _d.decode = Tool('before_request_body', encoding.decode) # the order of encoding, gzip, caching is important _d.encode = Tool('before_handler', encoding.ResponseEncoder, priority=70) _d.gzip = Tool('before_finalize', encoding.gzip, priority=80) _d.staticdir = HandlerTool(static.staticdir) _d.staticfile = HandlerTool(static.staticfile) _d.sessions = SessionTool() _d.xmlrpc = ErrorTool(_xmlrpc.on_error) _d.caching = CachingTool('before_handler', _caching.get, 'caching') _d.expires = Tool('before_finalize', _caching.expires) _d.tidy = DeprecatedTool( 'before_finalize', 'The tidy tool has been removed from the standard distribution of ' 'CherryPy. The most recent version can be found at ' 'http://tools.cherrypy.org/browser.') _d.nsgmls = DeprecatedTool( 'before_finalize', 'The nsgmls tool has been removed from the standard distribution of ' 'CherryPy. The most recent version can be found at ' 'http://tools.cherrypy.org/browser.') _d.ignore_headers = Tool('before_request_body', cptools.ignore_headers) _d.referer = Tool('before_request_body', cptools.referer) _d.basic_auth = Tool('on_start_resource', auth.basic_auth) _d.digest_auth = Tool('on_start_resource', auth.digest_auth) _d.trailing_slash = Tool('before_handler', cptools.trailing_slash, priority=60) _d.flatten = Tool('before_finalize', cptools.flatten) _d.accept = Tool('on_start_resource', cptools.accept) _d.redirect = Tool('on_start_resource', cptools.redirect) _d.autovary = Tool('on_start_resource', cptools.autovary, priority=0) _d.json_in = Tool('before_request_body', jsontools.json_in, priority=30) _d.json_out = Tool('before_handler', jsontools.json_out, priority=30) _d.auth_basic = Tool('before_handler', auth_basic.basic_auth, priority=1) _d.auth_digest = Tool('before_handler', auth_digest.digest_auth, priority=1) _d.params = Tool('before_handler', cptools.convert_params) del _d, cptools, encoding, auth, static SABnzbd-2.3.2/cherrypy/_cptree.py0000644000000000000000000002423213217005257014774 0ustar 00000000000000"""CherryPy Application and Tree objects.""" import os import six import cherrypy from cherrypy._cpcompat import ntou from cherrypy import _cpconfig, _cplogging, _cprequest, _cpwsgi, tools from cherrypy.lib import httputil class Application(object): """A CherryPy Application. Servers and gateways should not instantiate Request objects directly. Instead, they should ask an Application object for a request object. An instance of this class may also be used as a WSGI callable (WSGI application object) for itself. """ root = None """The top-most container of page handlers for this app. Handlers should be arranged in a hierarchy of attributes, matching the expected URI hierarchy; the default dispatcher then searches this hierarchy for a matching handler. When using a dispatcher other than the default, this value may be None.""" config = {} """A dict of {path: pathconf} pairs, where 'pathconf' is itself a dict of {key: value} pairs.""" namespaces = _cpconfig.NamespaceSet() toolboxes = {'tools': cherrypy.tools} log = None """A LogManager instance. See _cplogging.""" wsgiapp = None """A CPWSGIApp instance. See _cpwsgi.""" request_class = _cprequest.Request response_class = _cprequest.Response relative_urls = False def __init__(self, root, script_name='', config=None): self.log = _cplogging.LogManager(id(self), cherrypy.log.logger_root) self.root = root self.script_name = script_name self.wsgiapp = _cpwsgi.CPWSGIApp(self) self.namespaces = self.namespaces.copy() self.namespaces['log'] = lambda k, v: setattr(self.log, k, v) self.namespaces['wsgi'] = self.wsgiapp.namespace_handler self.config = self.__class__.config.copy() if config: self.merge(config) def __repr__(self): return '%s.%s(%r, %r)' % (self.__module__, self.__class__.__name__, self.root, self.script_name) script_name_doc = """The URI "mount point" for this app. A mount point is that portion of the URI which is constant for all URIs that are serviced by this application; it does not include scheme, host, or proxy ("virtual host") portions of the URI. For example, if script_name is "/my/cool/app", then the URL "http://www.example.com/my/cool/app/page1" might be handled by a "page1" method on the root object. The value of script_name MUST NOT end in a slash. If the script_name refers to the root of the URI, it MUST be an empty string (not "/"). If script_name is explicitly set to None, then the script_name will be provided for each call from request.wsgi_environ['SCRIPT_NAME']. """ def _get_script_name(self): if self._script_name is not None: return self._script_name # A `_script_name` with a value of None signals that the script name # should be pulled from WSGI environ. return cherrypy.serving.request.wsgi_environ['SCRIPT_NAME'].rstrip('/') def _set_script_name(self, value): if value: value = value.rstrip('/') self._script_name = value script_name = property(fget=_get_script_name, fset=_set_script_name, doc=script_name_doc) def merge(self, config): """Merge the given config into self.config.""" _cpconfig.merge(self.config, config) # Handle namespaces specified in config. self.namespaces(self.config.get('/', {})) def find_config(self, path, key, default=None): """Return the most-specific value for key along path, or default.""" trail = path or '/' while trail: nodeconf = self.config.get(trail, {}) if key in nodeconf: return nodeconf[key] lastslash = trail.rfind('/') if lastslash == -1: break elif lastslash == 0 and trail != '/': trail = '/' else: trail = trail[:lastslash] return default def get_serving(self, local, remote, scheme, sproto): """Create and return a Request and Response object.""" req = self.request_class(local, remote, scheme, sproto) req.app = self for name, toolbox in self.toolboxes.items(): req.namespaces[name] = toolbox resp = self.response_class() cherrypy.serving.load(req, resp) cherrypy.engine.publish('acquire_thread') cherrypy.engine.publish('before_request') return req, resp def release_serving(self): """Release the current serving (request and response).""" req = cherrypy.serving.request cherrypy.engine.publish('after_request') try: req.close() except: cherrypy.log(traceback=True, severity=40) cherrypy.serving.clear() def __call__(self, environ, start_response): return self.wsgiapp(environ, start_response) class Tree(object): """A registry of CherryPy applications, mounted at diverse points. An instance of this class may also be used as a WSGI callable (WSGI application object), in which case it dispatches to all mounted apps. """ apps = {} """ A dict of the form {script name: application}, where "script name" is a string declaring the URI mount point (no trailing slash), and "application" is an instance of cherrypy.Application (or an arbitrary WSGI callable if you happen to be using a WSGI server).""" def __init__(self): self.apps = {} def mount(self, root, script_name='', config=None): """Mount a new app from a root object, script_name, and config. root An instance of a "controller class" (a collection of page handler methods) which represents the root of the application. This may also be an Application instance, or None if using a dispatcher other than the default. script_name A string containing the "mount point" of the application. This should start with a slash, and be the path portion of the URL at which to mount the given root. For example, if root.index() will handle requests to "http://www.example.com:8080/dept/app1/", then the script_name argument would be "/dept/app1". It MUST NOT end in a slash. If the script_name refers to the root of the URI, it MUST be an empty string (not "/"). config A file or dict containing application config. """ if script_name is None: raise TypeError( "The 'script_name' argument may not be None. Application " 'objects may, however, possess a script_name of None (in ' 'order to inpect the WSGI environ for SCRIPT_NAME upon each ' 'request). You cannot mount such Applications on this Tree; ' 'you must pass them to a WSGI server interface directly.') # Next line both 1) strips trailing slash and 2) maps "/" -> "". script_name = script_name.rstrip('/') if isinstance(root, Application): app = root if script_name != '' and script_name != app.script_name: raise ValueError( 'Cannot specify a different script name and pass an ' 'Application instance to cherrypy.mount') script_name = app.script_name else: app = Application(root, script_name) # If mounted at "", add favicon.ico if (script_name == '' and root is not None and not hasattr(root, 'favicon_ico')): favicon = os.path.join(os.getcwd(), os.path.dirname(__file__), 'favicon.ico') root.favicon_ico = tools.staticfile.handler(favicon) if config: app.merge(config) self.apps[script_name] = app return app def graft(self, wsgi_callable, script_name=''): """Mount a wsgi callable at the given script_name.""" # Next line both 1) strips trailing slash and 2) maps "/" -> "". script_name = script_name.rstrip('/') self.apps[script_name] = wsgi_callable def script_name(self, path=None): """The script_name of the app at the given path, or None. If path is None, cherrypy.request is used. """ if path is None: try: request = cherrypy.serving.request path = httputil.urljoin(request.script_name, request.path_info) except AttributeError: return None while True: if path in self.apps: return path if path == '': return None # Move one node up the tree and try again. path = path[:path.rfind('/')] def __call__(self, environ, start_response): # If you're calling this, then you're probably setting SCRIPT_NAME # to '' (some WSGI servers always set SCRIPT_NAME to ''). # Try to look up the app using the full path. env1x = environ if six.PY2 and environ.get(ntou('wsgi.version')) == (ntou('u'), 0): env1x = _cpwsgi.downgrade_wsgi_ux_to_1x(environ) path = httputil.urljoin(env1x.get('SCRIPT_NAME', ''), env1x.get('PATH_INFO', '')) sn = self.script_name(path or '/') if sn is None: start_response('404 Not Found', []) return [] app = self.apps[sn] # Correct the SCRIPT_NAME and PATH_INFO environ entries. environ = environ.copy() if six.PY2 and environ.get(ntou('wsgi.version')) == (ntou('u'), 0): # Python 2/WSGI u.0: all strings MUST be of type unicode enc = environ[ntou('wsgi.url_encoding')] environ[ntou('SCRIPT_NAME')] = sn.decode(enc) environ[ntou('PATH_INFO')] = path[len(sn.rstrip('/')):].decode(enc) else: environ['SCRIPT_NAME'] = sn environ['PATH_INFO'] = path[len(sn.rstrip('/')):] return app(environ, start_response) SABnzbd-2.3.2/cherrypy/_cpwsgi.py0000644000000000000000000004063013217005257015006 0ustar 00000000000000"""WSGI interface (see PEP 333 and 3333). Note that WSGI environ keys and values are 'native strings'; that is, whatever the type of "" is. For Python 2, that's a byte string; for Python 3, it's a unicode string. But PEP 3333 says: "even if Python's str type is actually Unicode "under the hood", the content of native strings must still be translatable to bytes via the Latin-1 encoding!" """ import sys as _sys import io import six import cherrypy as _cherrypy from cherrypy._cpcompat import ntob, ntou from cherrypy import _cperror from cherrypy.lib import httputil from cherrypy.lib import is_closable_iterator def downgrade_wsgi_ux_to_1x(environ): """Return a new environ dict for WSGI 1.x from the given WSGI u.x environ. """ env1x = {} url_encoding = environ[ntou('wsgi.url_encoding')] for k, v in list(environ.items()): if k in [ntou('PATH_INFO'), ntou('SCRIPT_NAME'), ntou('QUERY_STRING')]: v = v.encode(url_encoding) elif isinstance(v, six.text_type): v = v.encode('ISO-8859-1') env1x[k.encode('ISO-8859-1')] = v return env1x class VirtualHost(object): """Select a different WSGI application based on the Host header. This can be useful when running multiple sites within one CP server. It allows several domains to point to different applications. For example:: root = Root() RootApp = cherrypy.Application(root) Domain2App = cherrypy.Application(root) SecureApp = cherrypy.Application(Secure()) vhost = cherrypy._cpwsgi.VirtualHost( RootApp, domains={ 'www.domain2.example': Domain2App, 'www.domain2.example:443': SecureApp, }, ) cherrypy.tree.graft(vhost) """ default = None """Required. The default WSGI application.""" use_x_forwarded_host = True """If True (the default), any "X-Forwarded-Host" request header will be used instead of the "Host" header. This is commonly added by HTTP servers (such as Apache) when proxying.""" domains = {} """A dict of {host header value: application} pairs. The incoming "Host" request header is looked up in this dict, and, if a match is found, the corresponding WSGI application will be called instead of the default. Note that you often need separate entries for "example.com" and "www.example.com". In addition, "Host" headers may contain the port number. """ def __init__(self, default, domains=None, use_x_forwarded_host=True): self.default = default self.domains = domains or {} self.use_x_forwarded_host = use_x_forwarded_host def __call__(self, environ, start_response): domain = environ.get('HTTP_HOST', '') if self.use_x_forwarded_host: domain = environ.get('HTTP_X_FORWARDED_HOST', domain) nextapp = self.domains.get(domain) if nextapp is None: nextapp = self.default return nextapp(environ, start_response) class InternalRedirector(object): """WSGI middleware that handles raised cherrypy.InternalRedirect.""" def __init__(self, nextapp, recursive=False): self.nextapp = nextapp self.recursive = recursive def __call__(self, environ, start_response): redirections = [] while True: environ = environ.copy() try: return self.nextapp(environ, start_response) except _cherrypy.InternalRedirect: ir = _sys.exc_info()[1] sn = environ.get('SCRIPT_NAME', '') path = environ.get('PATH_INFO', '') qs = environ.get('QUERY_STRING', '') # Add the *previous* path_info + qs to redirections. old_uri = sn + path if qs: old_uri += '?' + qs redirections.append(old_uri) if not self.recursive: # Check to see if the new URI has been redirected to # already new_uri = sn + ir.path if ir.query_string: new_uri += '?' + ir.query_string if new_uri in redirections: ir.request.close() tmpl = ( 'InternalRedirector visited the same URL twice: %r' ) raise RuntimeError(tmpl % new_uri) # Munge the environment and try again. environ['REQUEST_METHOD'] = 'GET' environ['PATH_INFO'] = ir.path environ['QUERY_STRING'] = ir.query_string environ['wsgi.input'] = io.BytesIO() environ['CONTENT_LENGTH'] = '0' environ['cherrypy.previous_request'] = ir.request class ExceptionTrapper(object): """WSGI middleware that traps exceptions.""" def __init__(self, nextapp, throws=(KeyboardInterrupt, SystemExit)): self.nextapp = nextapp self.throws = throws def __call__(self, environ, start_response): return _TrappedResponse( self.nextapp, environ, start_response, self.throws ) class _TrappedResponse(object): response = iter([]) def __init__(self, nextapp, environ, start_response, throws): self.nextapp = nextapp self.environ = environ self.start_response = start_response self.throws = throws self.started_response = False self.response = self.trap( self.nextapp, self.environ, self.start_response, ) self.iter_response = iter(self.response) def __iter__(self): self.started_response = True return self def __next__(self): return self.trap(next, self.iter_response) # todo: https://pythonhosted.org/six/#six.Iterator if six.PY2: next = __next__ def close(self): if hasattr(self.response, 'close'): self.response.close() def trap(self, func, *args, **kwargs): try: return func(*args, **kwargs) except self.throws: raise except StopIteration: raise except: tb = _cperror.format_exc() _cherrypy.log(tb, severity=40) if not _cherrypy.request.show_tracebacks: tb = '' s, h, b = _cperror.bare_error(tb) if six.PY3: # What fun. s = s.decode('ISO-8859-1') h = [ (k.decode('ISO-8859-1'), v.decode('ISO-8859-1')) for k, v in h ] if self.started_response: # Empty our iterable (so future calls raise StopIteration) self.iter_response = iter([]) else: self.iter_response = iter(b) try: self.start_response(s, h, _sys.exc_info()) except: # "The application must not trap any exceptions raised by # start_response, if it called start_response with exc_info. # Instead, it should allow such exceptions to propagate # back to the server or gateway." # But we still log and call close() to clean up ourselves. _cherrypy.log(traceback=True, severity=40) raise if self.started_response: return ntob('').join(b) else: return b # WSGI-to-CP Adapter # class AppResponse(object): """WSGI response iterable for CherryPy applications.""" def __init__(self, environ, start_response, cpapp): self.cpapp = cpapp try: if six.PY2: if environ.get(ntou('wsgi.version')) == (ntou('u'), 0): environ = downgrade_wsgi_ux_to_1x(environ) self.environ = environ self.run() r = _cherrypy.serving.response outstatus = r.output_status if not isinstance(outstatus, bytes): raise TypeError('response.output_status is not a byte string.') outheaders = [] for k, v in r.header_list: if not isinstance(k, bytes): tmpl = 'response.header_list key %r is not a byte string.' raise TypeError(tmpl % k) if not isinstance(v, bytes): tmpl = ( 'response.header_list value %r is not a byte string.' ) raise TypeError(tmpl % v) outheaders.append((k, v)) if six.PY3: # According to PEP 3333, when using Python 3, the response # status and headers must be bytes masquerading as unicode; # that is, they must be of type "str" but are restricted to # code points in the "latin-1" set. outstatus = outstatus.decode('ISO-8859-1') outheaders = [ (k.decode('ISO-8859-1'), v.decode('ISO-8859-1')) for k, v in outheaders ] self.iter_response = iter(r.body) self.write = start_response(outstatus, outheaders) except: self.close() raise def __iter__(self): return self def __next__(self): return next(self.iter_response) # todo: https://pythonhosted.org/six/#six.Iterator if six.PY2: next = __next__ def close(self): """Close and de-reference the current request and response. (Core)""" streaming = _cherrypy.serving.response.stream self.cpapp.release_serving() # We avoid the expense of examining the iterator to see if it's # closable unless we are streaming the response, as that's the # only situation where we are going to have an iterator which # may not have been exhausted yet. if streaming and is_closable_iterator(self.iter_response): iter_close = self.iter_response.close try: iter_close() except Exception: _cherrypy.log(traceback=True, severity=40) def run(self): """Create a Request object using environ.""" env = self.environ.get local = httputil.Host( '', int(env('SERVER_PORT', 80) or -1), env('SERVER_NAME', ''), ) remote = httputil.Host( env('REMOTE_ADDR', ''), int(env('REMOTE_PORT', -1) or -1), env('REMOTE_HOST', ''), ) scheme = env('wsgi.url_scheme') sproto = env('ACTUAL_SERVER_PROTOCOL', 'HTTP/1.1') request, resp = self.cpapp.get_serving(local, remote, scheme, sproto) # LOGON_USER is served by IIS, and is the name of the # user after having been mapped to a local account. # Both IIS and Apache set REMOTE_USER, when possible. request.login = env('LOGON_USER') or env('REMOTE_USER') or None request.multithread = self.environ['wsgi.multithread'] request.multiprocess = self.environ['wsgi.multiprocess'] request.wsgi_environ = self.environ request.prev = env('cherrypy.previous_request', None) meth = self.environ['REQUEST_METHOD'] path = httputil.urljoin( self.environ.get('SCRIPT_NAME', ''), self.environ.get('PATH_INFO', ''), ) qs = self.environ.get('QUERY_STRING', '') path, qs = self.recode_path_qs(path, qs) or (path, qs) rproto = self.environ.get('SERVER_PROTOCOL') headers = self.translate_headers(self.environ) rfile = self.environ['wsgi.input'] request.run(meth, path, qs, rproto, headers, rfile) headerNames = { 'HTTP_CGI_AUTHORIZATION': 'Authorization', 'CONTENT_LENGTH': 'Content-Length', 'CONTENT_TYPE': 'Content-Type', 'REMOTE_HOST': 'Remote-Host', 'REMOTE_ADDR': 'Remote-Addr', } def recode_path_qs(self, path, qs): if not six.PY3: return # This isn't perfect; if the given PATH_INFO is in the # wrong encoding, it may fail to match the appropriate config # section URI. But meh. old_enc = self.environ.get('wsgi.url_encoding', 'ISO-8859-1') new_enc = self.cpapp.find_config( self.environ.get('PATH_INFO', ''), 'request.uri_encoding', 'utf-8', ) if new_enc.lower() == old_enc.lower(): return # Even though the path and qs are unicode, the WSGI server # is required by PEP 3333 to coerce them to ISO-8859-1 # masquerading as unicode. So we have to encode back to # bytes and then decode again using the "correct" encoding. try: return ( path.encode(old_enc).decode(new_enc), qs.encode(old_enc).decode(new_enc), ) except (UnicodeEncodeError, UnicodeDecodeError): # Just pass them through without transcoding and hope. pass def translate_headers(self, environ): """Translate CGI-environ header names to HTTP header names.""" for cgiName in environ: # We assume all incoming header keys are uppercase already. if cgiName in self.headerNames: yield self.headerNames[cgiName], environ[cgiName] elif cgiName[:5] == 'HTTP_': # Hackish attempt at recovering original header names. translatedHeader = cgiName[5:].replace('_', '-') yield translatedHeader, environ[cgiName] class CPWSGIApp(object): """A WSGI application object for a CherryPy Application.""" pipeline = [ ('ExceptionTrapper', ExceptionTrapper), ('InternalRedirector', InternalRedirector), ] """A list of (name, wsgiapp) pairs. Each 'wsgiapp' MUST be a constructor that takes an initial, positional 'nextapp' argument, plus optional keyword arguments, and returns a WSGI application (that takes environ and start_response arguments). The 'name' can be any you choose, and will correspond to keys in self.config.""" head = None """Rather than nest all apps in the pipeline on each call, it's only done the first time, and the result is memoized into self.head. Set this to None again if you change self.pipeline after calling self.""" config = {} """A dict whose keys match names listed in the pipeline. Each value is a further dict which will be passed to the corresponding named WSGI callable (from the pipeline) as keyword arguments.""" response_class = AppResponse """The class to instantiate and return as the next app in the WSGI chain. """ def __init__(self, cpapp, pipeline=None): self.cpapp = cpapp self.pipeline = self.pipeline[:] if pipeline: self.pipeline.extend(pipeline) self.config = self.config.copy() def tail(self, environ, start_response): """WSGI application callable for the actual CherryPy application. You probably shouldn't call this; call self.__call__ instead, so that any WSGI middleware in self.pipeline can run first. """ return self.response_class(environ, start_response, self.cpapp) def __call__(self, environ, start_response): head = self.head if head is None: # Create and nest the WSGI apps in our pipeline (in reverse order). # Then memoize the result in self.head. head = self.tail for name, callable in self.pipeline[::-1]: conf = self.config.get(name, {}) head = callable(head, **conf) self.head = head return head(environ, start_response) def namespace_handler(self, k, v): """Config handler for the 'wsgi' namespace.""" if k == 'pipeline': # Note this allows multiple 'wsgi.pipeline' config entries # (but each entry will be processed in a 'random' order). # It should also allow developers to set default middleware # in code (passed to self.__init__) that deployers can add to # (but not remove) via config. self.pipeline.extend(v) elif k == 'response_class': self.response_class = v else: name, arg = k.split('.', 1) bucket = self.config.setdefault(name, {}) bucket[arg] = v SABnzbd-2.3.2/cherrypy/_cpwsgi_server.py0000644000000000000000000000571713217005257016403 0ustar 00000000000000"""WSGI server interface (see PEP 333). This adds some CP-specific bits to the framework-agnostic wsgiserver package. """ import sys import cherrypy from cherrypy import wsgiserver class CPWSGIServer(wsgiserver.CherryPyWSGIServer): """Wrapper for wsgiserver.CherryPyWSGIServer. wsgiserver has been designed to not reference CherryPy in any way, so that it can be used in other frameworks and applications. Therefore, we wrap it here, so we can set our own mount points from cherrypy.tree and apply some attributes from config -> cherrypy.server -> wsgiserver. """ def __init__(self, server_adapter=cherrypy.server): self.server_adapter = server_adapter self.max_request_header_size = ( self.server_adapter.max_request_header_size or 0 ) self.max_request_body_size = ( self.server_adapter.max_request_body_size or 0 ) server_name = (self.server_adapter.socket_host or self.server_adapter.socket_file or None) self.wsgi_version = self.server_adapter.wsgi_version s = wsgiserver.CherryPyWSGIServer s.__init__(self, server_adapter.bind_addr, cherrypy.tree, self.server_adapter.thread_pool, server_name, max=self.server_adapter.thread_pool_max, request_queue_size=self.server_adapter.socket_queue_size, timeout=self.server_adapter.socket_timeout, shutdown_timeout=self.server_adapter.shutdown_timeout, accepted_queue_size=self.server_adapter.accepted_queue_size, accepted_queue_timeout=self.server_adapter.accepted_queue_timeout, ) self.protocol = self.server_adapter.protocol_version self.nodelay = self.server_adapter.nodelay if sys.version_info >= (3, 0): ssl_module = self.server_adapter.ssl_module or 'builtin' else: ssl_module = self.server_adapter.ssl_module or 'pyopenssl' if self.server_adapter.ssl_context: adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module) self.ssl_adapter = adapter_class( self.server_adapter.ssl_certificate, self.server_adapter.ssl_private_key, self.server_adapter.ssl_certificate_chain) self.ssl_adapter.context = self.server_adapter.ssl_context elif self.server_adapter.ssl_certificate: adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module) self.ssl_adapter = adapter_class( self.server_adapter.ssl_certificate, self.server_adapter.ssl_private_key, self.server_adapter.ssl_certificate_chain) self.stats['Enabled'] = getattr( self.server_adapter, 'statistics', False) def error_log(self, msg='', level=20, traceback=False): cherrypy.engine.log(msg, level, traceback) SABnzbd-2.3.2/cherrypy/_helper.py0000644000000000000000000002414213217005257014771 0ustar 00000000000000""" Helper functions for CP apps """ import six from cherrypy._cpcompat import urljoin as _urljoin, urlencode as _urlencode from cherrypy._cpcompat import text_or_bytes import cherrypy def expose(func=None, alias=None): """ Expose the function or class, optionally providing an alias or set of aliases. """ def expose_(func): func.exposed = True if alias is not None: if isinstance(alias, text_or_bytes): parents[alias.replace('.', '_')] = func else: for a in alias: parents[a.replace('.', '_')] = func return func import sys import types decoratable_types = types.FunctionType, types.MethodType, type, if six.PY2: # Old-style classes are type types.ClassType. decoratable_types += types.ClassType, if isinstance(func, decoratable_types): if alias is None: # @expose func.exposed = True return func else: # func = expose(func, alias) parents = sys._getframe(1).f_locals return expose_(func) elif func is None: if alias is None: # @expose() parents = sys._getframe(1).f_locals return expose_ else: # @expose(alias="alias") or # @expose(alias=["alias1", "alias2"]) parents = sys._getframe(1).f_locals return expose_ else: # @expose("alias") or # @expose(["alias1", "alias2"]) parents = sys._getframe(1).f_locals alias = func return expose_ def popargs(*args, **kwargs): """A decorator for _cp_dispatch (cherrypy.dispatch.Dispatcher.dispatch_method_name). Optional keyword argument: handler=(Object or Function) Provides a _cp_dispatch function that pops off path segments into cherrypy.request.params under the names specified. The dispatch is then forwarded on to the next vpath element. Note that any existing (and exposed) member function of the class that popargs is applied to will override that value of the argument. For instance, if you have a method named "list" on the class decorated with popargs, then accessing "/list" will call that function instead of popping it off as the requested parameter. This restriction applies to all _cp_dispatch functions. The only way around this restriction is to create a "blank class" whose only function is to provide _cp_dispatch. If there are path elements after the arguments, or more arguments are requested than are available in the vpath, then the 'handler' keyword argument specifies the next object to handle the parameterized request. If handler is not specified or is None, then self is used. If handler is a function rather than an instance, then that function will be called with the args specified and the return value from that function used as the next object INSTEAD of adding the parameters to cherrypy.request.args. This decorator may be used in one of two ways: As a class decorator: @cherrypy.popargs('year', 'month', 'day') class Blog: def index(self, year=None, month=None, day=None): #Process the parameters here; any url like #/, /2009, /2009/12, or /2009/12/31 #will fill in the appropriate parameters. def create(self): #This link will still be available at /create. Defined functions #take precedence over arguments. Or as a member of a class: class Blog: _cp_dispatch = cherrypy.popargs('year', 'month', 'day') #... The handler argument may be used to mix arguments with built in functions. For instance, the following setup allows different activities at the day, month, and year level: class DayHandler: def index(self, year, month, day): #Do something with this day; probably list entries def delete(self, year, month, day): #Delete all entries for this day @cherrypy.popargs('day', handler=DayHandler()) class MonthHandler: def index(self, year, month): #Do something with this month; probably list entries def delete(self, year, month): #Delete all entries for this month @cherrypy.popargs('month', handler=MonthHandler()) class YearHandler: def index(self, year): #Do something with this year #... @cherrypy.popargs('year', handler=YearHandler()) class Root: def index(self): #... """ # Since keyword arg comes after *args, we have to process it ourselves # for lower versions of python. handler = None handler_call = False for k, v in kwargs.items(): if k == 'handler': handler = v else: raise TypeError( "cherrypy.popargs() got an unexpected keyword argument '{0}'" .format(k) ) import inspect if handler is not None \ and (hasattr(handler, '__call__') or inspect.isclass(handler)): handler_call = True def decorated(cls_or_self=None, vpath=None): if inspect.isclass(cls_or_self): # cherrypy.popargs is a class decorator cls = cls_or_self setattr(cls, cherrypy.dispatch.Dispatcher.dispatch_method_name, decorated) return cls # We're in the actual function self = cls_or_self parms = {} for arg in args: if not vpath: break parms[arg] = vpath.pop(0) if handler is not None: if handler_call: return handler(**parms) else: cherrypy.request.params.update(parms) return handler cherrypy.request.params.update(parms) # If we are the ultimate handler, then to prevent our _cp_dispatch # from being called again, we will resolve remaining elements through # getattr() directly. if vpath: return getattr(self, vpath.pop(0), None) else: return self return decorated def url(path='', qs='', script_name=None, base=None, relative=None): """Create an absolute URL for the given path. If 'path' starts with a slash ('/'), this will return (base + script_name + path + qs). If it does not start with a slash, this returns (base + script_name [+ request.path_info] + path + qs). If script_name is None, cherrypy.request will be used to find a script_name, if available. If base is None, cherrypy.request.base will be used (if available). Note that you can use cherrypy.tools.proxy to change this. Finally, note that this function can be used to obtain an absolute URL for the current request path (minus the querystring) by passing no args. If you call url(qs=cherrypy.request.query_string), you should get the original browser URL (assuming no internal redirections). If relative is None or not provided, request.app.relative_urls will be used (if available, else False). If False, the output will be an absolute URL (including the scheme, host, vhost, and script_name). If True, the output will instead be a URL that is relative to the current request path, perhaps including '..' atoms. If relative is the string 'server', the output will instead be a URL that is relative to the server root; i.e., it will start with a slash. """ if isinstance(qs, (tuple, list, dict)): qs = _urlencode(qs) if qs: qs = '?' + qs if cherrypy.request.app: if not path.startswith('/'): # Append/remove trailing slash from path_info as needed # (this is to support mistyped URL's without redirecting; # if you want to redirect, use tools.trailing_slash). pi = cherrypy.request.path_info if cherrypy.request.is_index is True: if not pi.endswith('/'): pi = pi + '/' elif cherrypy.request.is_index is False: if pi.endswith('/') and pi != '/': pi = pi[:-1] if path == '': path = pi else: path = _urljoin(pi, path) if script_name is None: script_name = cherrypy.request.script_name if base is None: base = cherrypy.request.base newurl = base + script_name + path + qs else: # No request.app (we're being called outside a request). # We'll have to guess the base from server.* attributes. # This will produce very different results from the above # if you're using vhosts or tools.proxy. if base is None: base = cherrypy.server.base() path = (script_name or '') + path newurl = base + path + qs if './' in newurl: # Normalize the URL by removing ./ and ../ atoms = [] for atom in newurl.split('/'): if atom == '.': pass elif atom == '..': atoms.pop() else: atoms.append(atom) newurl = '/'.join(atoms) # At this point, we should have a fully-qualified absolute URL. if relative is None: relative = getattr(cherrypy.request.app, 'relative_urls', False) # See http://www.ietf.org/rfc/rfc2396.txt if relative == 'server': # "A relative reference beginning with a single slash character is # termed an absolute-path reference, as defined by ..." # This is also sometimes called "server-relative". newurl = '/' + '/'.join(newurl.split('/', 3)[3:]) elif relative: # "A relative reference that does not begin with a scheme name # or a slash character is termed a relative-path reference." old = url(relative=False).split('/')[:-1] new = newurl.split('/') while old and new: a, b = old[0], new[0] if a != b: break old.pop(0) new.pop(0) new = (['..'] * len(old)) + new newurl = '/'.join(new) return newurl SABnzbd-2.3.2/cherrypy/__init__.py0000644000000000000000000002703713217005257015120 0ustar 00000000000000"""CherryPy is a pythonic, object-oriented HTTP framework. CherryPy consists of not one, but four separate API layers. The APPLICATION LAYER is the simplest. CherryPy applications are written as a tree of classes and methods, where each branch in the tree corresponds to a branch in the URL path. Each method is a 'page handler', which receives GET and POST params as keyword arguments, and returns or yields the (HTML) body of the response. The special method name 'index' is used for paths that end in a slash, and the special method name 'default' is used to handle multiple paths via a single handler. This layer also includes: * the 'exposed' attribute (and cherrypy.expose) * cherrypy.quickstart() * _cp_config attributes * cherrypy.tools (including cherrypy.session) * cherrypy.url() The ENVIRONMENT LAYER is used by developers at all levels. It provides information about the current request and response, plus the application and server environment, via a (default) set of top-level objects: * cherrypy.request * cherrypy.response * cherrypy.engine * cherrypy.server * cherrypy.tree * cherrypy.config * cherrypy.thread_data * cherrypy.log * cherrypy.HTTPError, NotFound, and HTTPRedirect * cherrypy.lib The EXTENSION LAYER allows advanced users to construct and share their own plugins. It consists of: * Hook API * Tool API * Toolbox API * Dispatch API * Config Namespace API Finally, there is the CORE LAYER, which uses the core API's to construct the default components which are available at higher layers. You can think of the default components as the 'reference implementation' for CherryPy. Megaframeworks (and advanced users) may replace the default components with customized or extended components. The core API's are: * Application API * Engine API * Request API * Server API * WSGI API These API's are described in the `CherryPy specification `_. """ try: import pkg_resources except ImportError: pass from threading import local as _local from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect # noqa from cherrypy._cperror import NotFound, CherryPyException, TimeoutError # noqa from cherrypy import _cplogging from cherrypy import _cpdispatch as dispatch # noqa from cherrypy import _cptools from cherrypy._cptools import default_toolbox as tools, Tool from cherrypy import _cprequest from cherrypy.lib import httputil as _httputil from cherrypy import _cptree from cherrypy._cptree import Application # noqa from cherrypy import _cpwsgi as wsgi # noqa from cherrypy import _cpserver from cherrypy import process try: from cherrypy.process import win32 engine = win32.Win32Bus() engine.console_control_handler = win32.ConsoleCtrlHandler(engine) del win32 except ImportError: engine = process.bus tree = _cptree.Tree() __version__ = '8.1.2' # Timeout monitor. We add two channels to the engine # to which cherrypy.Application will publish. engine.listeners['before_request'] = set() engine.listeners['after_request'] = set() class _TimeoutMonitor(process.plugins.Monitor): def __init__(self, bus): self.servings = [] process.plugins.Monitor.__init__(self, bus, self.run) def before_request(self): self.servings.append((serving.request, serving.response)) def after_request(self): try: self.servings.remove((serving.request, serving.response)) except ValueError: pass def run(self): """Check timeout on all responses. (Internal)""" for req, resp in self.servings: resp.check_timeout() engine.timeout_monitor = _TimeoutMonitor(engine) engine.timeout_monitor.subscribe() engine.autoreload = process.plugins.Autoreloader(engine) engine.autoreload.subscribe() engine.thread_manager = process.plugins.ThreadManager(engine) engine.thread_manager.subscribe() engine.signal_handler = process.plugins.SignalHandler(engine) class _HandleSignalsPlugin(object): """Handle signals from other processes based on the configured platform handlers above.""" def __init__(self, bus): self.bus = bus def subscribe(self): """Add the handlers based on the platform""" if hasattr(self.bus, 'signal_handler'): self.bus.signal_handler.subscribe() if hasattr(self.bus, 'console_control_handler'): self.bus.console_control_handler.subscribe() engine.signals = _HandleSignalsPlugin(engine) server = _cpserver.Server() server.subscribe() def quickstart(root=None, script_name='', config=None): """Mount the given root, start the builtin server (and engine), then block. root: an instance of a "controller class" (a collection of page handler methods) which represents the root of the application. script_name: a string containing the "mount point" of the application. This should start with a slash, and be the path portion of the URL at which to mount the given root. For example, if root.index() will handle requests to "http://www.example.com:8080/dept/app1/", then the script_name argument would be "/dept/app1". It MUST NOT end in a slash. If the script_name refers to the root of the URI, it MUST be an empty string (not "/"). config: a file or dict containing application config. If this contains a [global] section, those entries will be used in the global (site-wide) config. """ if config: _global_conf_alias.update(config) tree.mount(root, script_name, config) engine.signals.subscribe() engine.start() engine.block() class _Serving(_local): """An interface for registering request and response objects. Rather than have a separate "thread local" object for the request and the response, this class works as a single threadlocal container for both objects (and any others which developers wish to define). In this way, we can easily dump those objects when we stop/start a new HTTP conversation, yet still refer to them as module-level globals in a thread-safe way. """ request = _cprequest.Request(_httputil.Host('127.0.0.1', 80), _httputil.Host('127.0.0.1', 1111)) """ The request object for the current thread. In the main thread, and any threads which are not receiving HTTP requests, this is None.""" response = _cprequest.Response() """ The response object for the current thread. In the main thread, and any threads which are not receiving HTTP requests, this is None.""" def load(self, request, response): self.request = request self.response = response def clear(self): """Remove all attributes of self.""" self.__dict__.clear() serving = _Serving() class _ThreadLocalProxy(object): __slots__ = ['__attrname__', '__dict__'] def __init__(self, attrname): self.__attrname__ = attrname def __getattr__(self, name): child = getattr(serving, self.__attrname__) return getattr(child, name) def __setattr__(self, name, value): if name in ('__attrname__', ): object.__setattr__(self, name, value) else: child = getattr(serving, self.__attrname__) setattr(child, name, value) def __delattr__(self, name): child = getattr(serving, self.__attrname__) delattr(child, name) def _get_dict(self): child = getattr(serving, self.__attrname__) d = child.__class__.__dict__.copy() d.update(child.__dict__) return d __dict__ = property(_get_dict) def __getitem__(self, key): child = getattr(serving, self.__attrname__) return child[key] def __setitem__(self, key, value): child = getattr(serving, self.__attrname__) child[key] = value def __delitem__(self, key): child = getattr(serving, self.__attrname__) del child[key] def __contains__(self, key): child = getattr(serving, self.__attrname__) return key in child def __len__(self): child = getattr(serving, self.__attrname__) return len(child) def __nonzero__(self): child = getattr(serving, self.__attrname__) return bool(child) # Python 3 __bool__ = __nonzero__ # Create request and response object (the same objects will be used # throughout the entire life of the webserver, but will redirect # to the "serving" object) request = _ThreadLocalProxy('request') response = _ThreadLocalProxy('response') # Create thread_data object as a thread-specific all-purpose storage class _ThreadData(_local): """A container for thread-specific data.""" thread_data = _ThreadData() # Monkeypatch pydoc to allow help() to go through the threadlocal proxy. # Jan 2007: no Googleable examples of anyone else replacing pydoc.resolve. # The only other way would be to change what is returned from type(request) # and that's not possible in pure Python (you'd have to fake ob_type). def _cherrypy_pydoc_resolve(thing, forceload=0): """Given an object or a path to an object, get the object and its name.""" if isinstance(thing, _ThreadLocalProxy): thing = getattr(serving, thing.__attrname__) return _pydoc._builtin_resolve(thing, forceload) try: import pydoc as _pydoc _pydoc._builtin_resolve = _pydoc.resolve _pydoc.resolve = _cherrypy_pydoc_resolve except ImportError: pass class _GlobalLogManager(_cplogging.LogManager): """A site-wide LogManager; routes to app.log or global log as appropriate. This :class:`LogManager` implements cherrypy.log() and cherrypy.log.access(). If either function is called during a request, the message will be sent to the logger for the current Application. If they are called outside of a request, the message will be sent to the site-wide logger. """ def __call__(self, *args, **kwargs): """Log the given message to the app.log or global log as appropriate. """ # Do NOT use try/except here. See # https://github.com/cherrypy/cherrypy/issues/945 if hasattr(request, 'app') and hasattr(request.app, 'log'): log = request.app.log else: log = self return log.error(*args, **kwargs) def access(self): """Log an access message to the app.log or global log as appropriate. """ try: return request.app.log.access() except AttributeError: return _cplogging.LogManager.access(self) log = _GlobalLogManager() # Set a default screen handler on the global log. log.screen = True log.error_file = '' # Using an access file makes CP about 10% slower. Leave off by default. log.access_file = '' def _buslog(msg, level): log.error(msg, 'ENGINE', severity=level) engine.subscribe('log', _buslog) from cherrypy._helper import expose, popargs, url # noqa # import _cpconfig last so it can reference other top-level objects from cherrypy import _cpconfig # noqa # Use _global_conf_alias so quickstart can use 'config' as an arg # without shadowing cherrypy.config. config = _global_conf_alias = _cpconfig.Config() config.defaults = { 'tools.log_tracebacks.on': True, 'tools.log_headers.on': True, 'tools.trailing_slash.on': True, 'tools.encode.on': True } config.namespaces['log'] = lambda k, v: setattr(log, k, v) config.namespaces['checker'] = lambda k, v: setattr(checker, k, v) # Must reset to get our defaults applied. config.reset() from cherrypy import _cpchecker # noqa checker = _cpchecker.Checker() engine.subscribe('start', checker) SABnzbd-2.3.2/cherrypy/__main__.py0000644000000000000000000000011513217005257015065 0ustar 00000000000000import cherrypy.daemon if __name__ == '__main__': cherrypy.daemon.run() SABnzbd-2.3.2/cherrypy/lib/auth.py0000644000000000000000000000623013217005257015060 0ustar 00000000000000import cherrypy from cherrypy.lib import httpauth def check_auth(users, encrypt=None, realm=None): """If an authorization header contains credentials, return True or False. """ request = cherrypy.serving.request if 'authorization' in request.headers: # make sure the provided credentials are correctly set ah = httpauth.parseAuthorization(request.headers['authorization']) if ah is None: raise cherrypy.HTTPError(400, 'Bad Request') if not encrypt: encrypt = httpauth.DIGEST_AUTH_ENCODERS[httpauth.MD5] if hasattr(users, '__call__'): try: # backward compatibility users = users() # expect it to return a dictionary if not isinstance(users, dict): raise ValueError( 'Authentication users must be a dictionary') # fetch the user password password = users.get(ah['username'], None) except TypeError: # returns a password (encrypted or clear text) password = users(ah['username']) else: if not isinstance(users, dict): raise ValueError('Authentication users must be a dictionary') # fetch the user password password = users.get(ah['username'], None) # validate the authorization by re-computing it here # and compare it with what the user-agent provided if httpauth.checkResponse(ah, password, method=request.method, encrypt=encrypt, realm=realm): request.login = ah['username'] return True request.login = False return False def basic_auth(realm, users, encrypt=None, debug=False): """If auth fails, raise 401 with a basic authentication header. realm A string containing the authentication realm. users A dict of the form: {username: password} or a callable returning a dict. encrypt callable used to encrypt the password returned from the user-agent. if None it defaults to a md5 encryption. """ if check_auth(users, encrypt): if debug: cherrypy.log('Auth successful', 'TOOLS.BASIC_AUTH') return # inform the user-agent this path is protected cherrypy.serving.response.headers[ 'www-authenticate'] = httpauth.basicAuth(realm) raise cherrypy.HTTPError( 401, 'You are not authorized to access that resource') def digest_auth(realm, users, debug=False): """If auth fails, raise 401 with a digest authentication header. realm A string containing the authentication realm. users A dict of the form: {username: password} or a callable returning a dict. """ if check_auth(users, realm=realm): if debug: cherrypy.log('Auth successful', 'TOOLS.DIGEST_AUTH') return # inform the user-agent this path is protected cherrypy.serving.response.headers[ 'www-authenticate'] = httpauth.digestAuth(realm) raise cherrypy.HTTPError( 401, 'You are not authorized to access that resource') SABnzbd-2.3.2/cherrypy/lib/auth_basic.py0000644000000000000000000000651313217005257016225 0ustar 00000000000000# This file is part of CherryPy # -*- coding: utf-8 -*- # vim:ts=4:sw=4:expandtab:fileencoding=utf-8 import binascii import cherrypy from cherrypy._cpcompat import base64_decode __doc__ = """This module provides a CherryPy 3.x tool which implements the server-side of HTTP Basic Access Authentication, as described in :rfc:`2617`. Example usage, using the built-in checkpassword_dict function which uses a dict as the credentials store:: userpassdict = {'bird' : 'bebop', 'ornette' : 'wayout'} checkpassword = cherrypy.lib.auth_basic.checkpassword_dict(userpassdict) basic_auth = {'tools.auth_basic.on': True, 'tools.auth_basic.realm': 'earth', 'tools.auth_basic.checkpassword': checkpassword, } app_config = { '/' : basic_auth } """ __author__ = 'visteya' __date__ = 'April 2009' def checkpassword_dict(user_password_dict): """Returns a checkpassword function which checks credentials against a dictionary of the form: {username : password}. If you want a simple dictionary-based authentication scheme, use checkpassword_dict(my_credentials_dict) as the value for the checkpassword argument to basic_auth(). """ def checkpassword(realm, user, password): p = user_password_dict.get(user) return p and p == password or False return checkpassword def basic_auth(realm, checkpassword, debug=False): """A CherryPy tool which hooks at before_handler to perform HTTP Basic Access Authentication, as specified in :rfc:`2617`. If the request has an 'authorization' header with a 'Basic' scheme, this tool attempts to authenticate the credentials supplied in that header. If the request has no 'authorization' header, or if it does but the scheme is not 'Basic', or if authentication fails, the tool sends a 401 response with a 'WWW-Authenticate' Basic header. realm A string containing the authentication realm. checkpassword A callable which checks the authentication credentials. Its signature is checkpassword(realm, username, password). where username and password are the values obtained from the request's 'authorization' header. If authentication succeeds, checkpassword returns True, else it returns False. """ if '"' in realm: raise ValueError('Realm cannot contain the " (quote) character.') request = cherrypy.serving.request auth_header = request.headers.get('authorization') if auth_header is not None: # split() error, base64.decodestring() error with cherrypy.HTTPError.handle((ValueError, binascii.Error), 400, 'Bad Request'): scheme, params = auth_header.split(' ', 1) if scheme.lower() == 'basic': username, password = base64_decode(params).split(':', 1) if checkpassword(realm, username, password): if debug: cherrypy.log('Auth succeeded', 'TOOLS.AUTH_BASIC') request.login = username return # successful authentication # Respond with 401 status and a WWW-Authenticate header cherrypy.serving.response.headers[ 'www-authenticate'] = 'Basic realm="%s"' % realm raise cherrypy.HTTPError( 401, 'You are not authorized to access that resource') SABnzbd-2.3.2/cherrypy/lib/auth_digest.py0000644000000000000000000003350613217005257016425 0ustar 00000000000000# This file is part of CherryPy # -*- coding: utf-8 -*- # vim:ts=4:sw=4:expandtab:fileencoding=utf-8 import time from hashlib import md5 import cherrypy from cherrypy._cpcompat import ntob, parse_http_list, parse_keqv_list __doc__ = """An implementation of the server-side of HTTP Digest Access Authentication, which is described in :rfc:`2617`. Example usage, using the built-in get_ha1_dict_plain function which uses a dict of plaintext passwords as the credentials store:: userpassdict = {'alice' : '4x5istwelve'} get_ha1 = cherrypy.lib.auth_digest.get_ha1_dict_plain(userpassdict) digest_auth = {'tools.auth_digest.on': True, 'tools.auth_digest.realm': 'wonderland', 'tools.auth_digest.get_ha1': get_ha1, 'tools.auth_digest.key': 'a565c27146791cfb', } app_config = { '/' : digest_auth } """ __author__ = 'visteya' __date__ = 'April 2009' md5_hex = lambda s: md5(ntob(s)).hexdigest() qop_auth = 'auth' qop_auth_int = 'auth-int' valid_qops = (qop_auth, qop_auth_int) valid_algorithms = ('MD5', 'MD5-sess') def TRACE(msg): cherrypy.log(msg, context='TOOLS.AUTH_DIGEST') # Three helper functions for users of the tool, providing three variants # of get_ha1() functions for three different kinds of credential stores. def get_ha1_dict_plain(user_password_dict): """Returns a get_ha1 function which obtains a plaintext password from a dictionary of the form: {username : password}. If you want a simple dictionary-based authentication scheme, with plaintext passwords, use get_ha1_dict_plain(my_userpass_dict) as the value for the get_ha1 argument to digest_auth(). """ def get_ha1(realm, username): password = user_password_dict.get(username) if password: return md5_hex('%s:%s:%s' % (username, realm, password)) return None return get_ha1 def get_ha1_dict(user_ha1_dict): """Returns a get_ha1 function which obtains a HA1 password hash from a dictionary of the form: {username : HA1}. If you want a dictionary-based authentication scheme, but with pre-computed HA1 hashes instead of plain-text passwords, use get_ha1_dict(my_userha1_dict) as the value for the get_ha1 argument to digest_auth(). """ def get_ha1(realm, username): return user_ha1_dict.get(username) return get_ha1 def get_ha1_file_htdigest(filename): """Returns a get_ha1 function which obtains a HA1 password hash from a flat file with lines of the same format as that produced by the Apache htdigest utility. For example, for realm 'wonderland', username 'alice', and password '4x5istwelve', the htdigest line would be:: alice:wonderland:3238cdfe91a8b2ed8e39646921a02d4c If you want to use an Apache htdigest file as the credentials store, then use get_ha1_file_htdigest(my_htdigest_file) as the value for the get_ha1 argument to digest_auth(). It is recommended that the filename argument be an absolute path, to avoid problems. """ def get_ha1(realm, username): result = None f = open(filename, 'r') for line in f: u, r, ha1 = line.rstrip().split(':') if u == username and r == realm: result = ha1 break f.close() return result return get_ha1 def synthesize_nonce(s, key, timestamp=None): """Synthesize a nonce value which resists spoofing and can be checked for staleness. Returns a string suitable as the value for 'nonce' in the www-authenticate header. s A string related to the resource, such as the hostname of the server. key A secret string known only to the server. timestamp An integer seconds-since-the-epoch timestamp """ if timestamp is None: timestamp = int(time.time()) h = md5_hex('%s:%s:%s' % (timestamp, s, key)) nonce = '%s:%s' % (timestamp, h) return nonce def H(s): """The hash function H""" return md5_hex(s) class HttpDigestAuthorization (object): """Class to parse a Digest Authorization header and perform re-calculation of the digest. """ def errmsg(self, s): return 'Digest Authorization header: %s' % s def __init__(self, auth_header, http_method, debug=False): self.http_method = http_method self.debug = debug scheme, params = auth_header.split(' ', 1) self.scheme = scheme.lower() if self.scheme != 'digest': raise ValueError('Authorization scheme is not "Digest"') self.auth_header = auth_header # make a dict of the params items = parse_http_list(params) paramsd = parse_keqv_list(items) self.realm = paramsd.get('realm') self.username = paramsd.get('username') self.nonce = paramsd.get('nonce') self.uri = paramsd.get('uri') self.method = paramsd.get('method') self.response = paramsd.get('response') # the response digest self.algorithm = paramsd.get('algorithm', 'MD5').upper() self.cnonce = paramsd.get('cnonce') self.opaque = paramsd.get('opaque') self.qop = paramsd.get('qop') # qop self.nc = paramsd.get('nc') # nonce count # perform some correctness checks if self.algorithm not in valid_algorithms: raise ValueError( self.errmsg("Unsupported value for algorithm: '%s'" % self.algorithm)) has_reqd = ( self.username and self.realm and self.nonce and self.uri and self.response ) if not has_reqd: raise ValueError( self.errmsg('Not all required parameters are present.')) if self.qop: if self.qop not in valid_qops: raise ValueError( self.errmsg("Unsupported value for qop: '%s'" % self.qop)) if not (self.cnonce and self.nc): raise ValueError( self.errmsg('If qop is sent then ' 'cnonce and nc MUST be present')) else: if self.cnonce or self.nc: raise ValueError( self.errmsg('If qop is not sent, ' 'neither cnonce nor nc can be present')) def __str__(self): return 'authorization : %s' % self.auth_header def validate_nonce(self, s, key): """Validate the nonce. Returns True if nonce was generated by synthesize_nonce() and the timestamp is not spoofed, else returns False. s A string related to the resource, such as the hostname of the server. key A secret string known only to the server. Both s and key must be the same values which were used to synthesize the nonce we are trying to validate. """ try: timestamp, hashpart = self.nonce.split(':', 1) s_timestamp, s_hashpart = synthesize_nonce( s, key, timestamp).split(':', 1) is_valid = s_hashpart == hashpart if self.debug: TRACE('validate_nonce: %s' % is_valid) return is_valid except ValueError: # split() error pass return False def is_nonce_stale(self, max_age_seconds=600): """Returns True if a validated nonce is stale. The nonce contains a timestamp in plaintext and also a secure hash of the timestamp. You should first validate the nonce to ensure the plaintext timestamp is not spoofed. """ try: timestamp, hashpart = self.nonce.split(':', 1) if int(timestamp) + max_age_seconds > int(time.time()): return False except ValueError: # int() error pass if self.debug: TRACE('nonce is stale') return True def HA2(self, entity_body=''): """Returns the H(A2) string. See :rfc:`2617` section 3.2.2.3.""" # RFC 2617 3.2.2.3 # If the "qop" directive's value is "auth" or is unspecified, # then A2 is: # A2 = method ":" digest-uri-value # # If the "qop" value is "auth-int", then A2 is: # A2 = method ":" digest-uri-value ":" H(entity-body) if self.qop is None or self.qop == 'auth': a2 = '%s:%s' % (self.http_method, self.uri) elif self.qop == 'auth-int': a2 = '%s:%s:%s' % (self.http_method, self.uri, H(entity_body)) else: # in theory, this should never happen, since I validate qop in # __init__() raise ValueError(self.errmsg('Unrecognized value for qop!')) return H(a2) def request_digest(self, ha1, entity_body=''): """Calculates the Request-Digest. See :rfc:`2617` section 3.2.2.1. ha1 The HA1 string obtained from the credentials store. entity_body If 'qop' is set to 'auth-int', then A2 includes a hash of the "entity body". The entity body is the part of the message which follows the HTTP headers. See :rfc:`2617` section 4.3. This refers to the entity the user agent sent in the request which has the Authorization header. Typically GET requests don't have an entity, and POST requests do. """ ha2 = self.HA2(entity_body) # Request-Digest -- RFC 2617 3.2.2.1 if self.qop: req = '%s:%s:%s:%s:%s' % ( self.nonce, self.nc, self.cnonce, self.qop, ha2) else: req = '%s:%s' % (self.nonce, ha2) # RFC 2617 3.2.2.2 # # If the "algorithm" directive's value is "MD5" or is unspecified, # then A1 is: # A1 = unq(username-value) ":" unq(realm-value) ":" passwd # # If the "algorithm" directive's value is "MD5-sess", then A1 is # calculated only once - on the first request by the client following # receipt of a WWW-Authenticate challenge from the server. # A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) # ":" unq(nonce-value) ":" unq(cnonce-value) if self.algorithm == 'MD5-sess': ha1 = H('%s:%s:%s' % (ha1, self.nonce, self.cnonce)) digest = H('%s:%s' % (ha1, req)) return digest def www_authenticate(realm, key, algorithm='MD5', nonce=None, qop=qop_auth, stale=False): """Constructs a WWW-Authenticate header for Digest authentication.""" if qop not in valid_qops: raise ValueError("Unsupported value for qop: '%s'" % qop) if algorithm not in valid_algorithms: raise ValueError("Unsupported value for algorithm: '%s'" % algorithm) if nonce is None: nonce = synthesize_nonce(realm, key) s = 'Digest realm="%s", nonce="%s", algorithm="%s", qop="%s"' % ( realm, nonce, algorithm, qop) if stale: s += ', stale="true"' return s def digest_auth(realm, get_ha1, key, debug=False): """A CherryPy tool which hooks at before_handler to perform HTTP Digest Access Authentication, as specified in :rfc:`2617`. If the request has an 'authorization' header with a 'Digest' scheme, this tool authenticates the credentials supplied in that header. If the request has no 'authorization' header, or if it does but the scheme is not "Digest", or if authentication fails, the tool sends a 401 response with a 'WWW-Authenticate' Digest header. realm A string containing the authentication realm. get_ha1 A callable which looks up a username in a credentials store and returns the HA1 string, which is defined in the RFC to be MD5(username : realm : password). The function's signature is: ``get_ha1(realm, username)`` where username is obtained from the request's 'authorization' header. If username is not found in the credentials store, get_ha1() returns None. key A secret string known only to the server, used in the synthesis of nonces. """ request = cherrypy.serving.request auth_header = request.headers.get('authorization') nonce_is_stale = False if auth_header is not None: with cherrypy.HTTPError.handle(ValueError, 400, 'The Authorization header could not be parsed.'): auth = HttpDigestAuthorization( auth_header, request.method, debug=debug) if debug: TRACE(str(auth)) if auth.validate_nonce(realm, key): ha1 = get_ha1(realm, auth.username) if ha1 is not None: # note that for request.body to be available we need to # hook in at before_handler, not on_start_resource like # 3.1.x digest_auth does. digest = auth.request_digest(ha1, entity_body=request.body) if digest == auth.response: # authenticated if debug: TRACE('digest matches auth.response') # Now check if nonce is stale. # The choice of ten minutes' lifetime for nonce is somewhat # arbitrary nonce_is_stale = auth.is_nonce_stale(max_age_seconds=600) if not nonce_is_stale: request.login = auth.username if debug: TRACE('authentication of %s successful' % auth.username) return # Respond with 401 status and a WWW-Authenticate header header = www_authenticate(realm, key, stale=nonce_is_stale) if debug: TRACE(header) cherrypy.serving.response.headers['WWW-Authenticate'] = header raise cherrypy.HTTPError( 401, 'You are not authorized to access that resource') SABnzbd-2.3.2/cherrypy/lib/caching.py0000644000000000000000000004135313217005257015520 0ustar 00000000000000""" CherryPy implements a simple caching system as a pluggable Tool. This tool tries to be an (in-process) HTTP/1.1-compliant cache. It's not quite there yet, but it's probably good enough for most sites. In general, GET responses are cached (along with selecting headers) and, if another request arrives for the same resource, the caching Tool will return 304 Not Modified if possible, or serve the cached response otherwise. It also sets request.cached to True if serving a cached representation, and sets request.cacheable to False (so it doesn't get cached again). If POST, PUT, or DELETE requests are made for a cached resource, they invalidate (delete) any cached response. Usage ===== Configuration file example:: [/] tools.caching.on = True tools.caching.delay = 3600 You may use a class other than the default :class:`MemoryCache` by supplying the config entry ``cache_class``; supply the full dotted name of the replacement class as the config value. It must implement the basic methods ``get``, ``put``, ``delete``, and ``clear``. You may set any attribute, including overriding methods, on the cache instance by providing them in config. The above sets the :attr:`delay` attribute, for example. """ import datetime import sys import threading import time import cherrypy from cherrypy.lib import cptools, httputil from cherrypy._cpcompat import copyitems, ntob, sorted, Event class Cache(object): """Base class for Cache implementations.""" def get(self): """Return the current variant if in the cache, else None.""" raise NotImplemented def put(self, obj, size): """Store the current variant in the cache.""" raise NotImplemented def delete(self): """Remove ALL cached variants of the current resource.""" raise NotImplemented def clear(self): """Reset the cache to its initial, empty state.""" raise NotImplemented # ------------------------------ Memory Cache ------------------------------- # class AntiStampedeCache(dict): """A storage system for cached items which reduces stampede collisions.""" def wait(self, key, timeout=5, debug=False): """Return the cached value for the given key, or None. If timeout is not None, and the value is already being calculated by another thread, wait until the given timeout has elapsed. If the value is available before the timeout expires, it is returned. If not, None is returned, and a sentinel placed in the cache to signal other threads to wait. If timeout is None, no waiting is performed nor sentinels used. """ value = self.get(key) if isinstance(value, Event): if timeout is None: # Ignore the other thread and recalc it ourselves. if debug: cherrypy.log('No timeout', 'TOOLS.CACHING') return None # Wait until it's done or times out. if debug: cherrypy.log('Waiting up to %s seconds' % timeout, 'TOOLS.CACHING') value.wait(timeout) if value.result is not None: # The other thread finished its calculation. Use it. if debug: cherrypy.log('Result!', 'TOOLS.CACHING') return value.result # Timed out. Stick an Event in the slot so other threads wait # on this one to finish calculating the value. if debug: cherrypy.log('Timed out', 'TOOLS.CACHING') e = threading.Event() e.result = None dict.__setitem__(self, key, e) return None elif value is None: # Stick an Event in the slot so other threads wait # on this one to finish calculating the value. if debug: cherrypy.log('Timed out', 'TOOLS.CACHING') e = threading.Event() e.result = None dict.__setitem__(self, key, e) return value def __setitem__(self, key, value): """Set the cached value for the given key.""" existing = self.get(key) dict.__setitem__(self, key, value) if isinstance(existing, Event): # Set Event.result so other threads waiting on it have # immediate access without needing to poll the cache again. existing.result = value existing.set() class MemoryCache(Cache): """An in-memory cache for varying response content. Each key in self.store is a URI, and each value is an AntiStampedeCache. The response for any given URI may vary based on the values of "selecting request headers"; that is, those named in the Vary response header. We assume the list of header names to be constant for each URI throughout the lifetime of the application, and store that list in ``self.store[uri].selecting_headers``. The items contained in ``self.store[uri]`` have keys which are tuples of request header values (in the same order as the names in its selecting_headers), and values which are the actual responses. """ maxobjects = 1000 """The maximum number of cached objects; defaults to 1000.""" maxobj_size = 100000 """The maximum size of each cached object in bytes; defaults to 100 KB.""" maxsize = 10000000 """The maximum size of the entire cache in bytes; defaults to 10 MB.""" delay = 600 """Seconds until the cached content expires; defaults to 600 (10 minutes). """ antistampede_timeout = 5 """Seconds to wait for other threads to release a cache lock.""" expire_freq = 0.1 """Seconds to sleep between cache expiration sweeps.""" debug = False def __init__(self): self.clear() # Run self.expire_cache in a separate daemon thread. t = threading.Thread(target=self.expire_cache, name='expire_cache') self.expiration_thread = t t.daemon = True t.start() def clear(self): """Reset the cache to its initial, empty state.""" self.store = {} self.expirations = {} self.tot_puts = 0 self.tot_gets = 0 self.tot_hist = 0 self.tot_expires = 0 self.tot_non_modified = 0 self.cursize = 0 def expire_cache(self): """Continuously examine cached objects, expiring stale ones. This function is designed to be run in its own daemon thread, referenced at ``self.expiration_thread``. """ # It's possible that "time" will be set to None # arbitrarily, so we check "while time" to avoid exceptions. # See tickets #99 and #180 for more information. while time: now = time.time() # Must make a copy of expirations so it doesn't change size # during iteration for expiration_time, objects in copyitems(self.expirations): if expiration_time <= now: for obj_size, uri, sel_header_values in objects: try: del self.store[uri][tuple(sel_header_values)] self.tot_expires += 1 self.cursize -= obj_size except KeyError: # the key may have been deleted elsewhere pass del self.expirations[expiration_time] time.sleep(self.expire_freq) def get(self): """Return the current variant if in the cache, else None.""" request = cherrypy.serving.request self.tot_gets += 1 uri = cherrypy.url(qs=request.query_string) uricache = self.store.get(uri) if uricache is None: return None header_values = [request.headers.get(h, '') for h in uricache.selecting_headers] variant = uricache.wait(key=tuple(sorted(header_values)), timeout=self.antistampede_timeout, debug=self.debug) if variant is not None: self.tot_hist += 1 return variant def put(self, variant, size): """Store the current variant in the cache.""" request = cherrypy.serving.request response = cherrypy.serving.response uri = cherrypy.url(qs=request.query_string) uricache = self.store.get(uri) if uricache is None: uricache = AntiStampedeCache() uricache.selecting_headers = [ e.value for e in response.headers.elements('Vary')] self.store[uri] = uricache if len(self.store) < self.maxobjects: total_size = self.cursize + size # checks if there's space for the object if (size < self.maxobj_size and total_size < self.maxsize): # add to the expirations list expiration_time = response.time + self.delay bucket = self.expirations.setdefault(expiration_time, []) bucket.append((size, uri, uricache.selecting_headers)) # add to the cache header_values = [request.headers.get(h, '') for h in uricache.selecting_headers] uricache[tuple(sorted(header_values))] = variant self.tot_puts += 1 self.cursize = total_size def delete(self): """Remove ALL cached variants of the current resource.""" uri = cherrypy.url(qs=cherrypy.serving.request.query_string) self.store.pop(uri, None) def get(invalid_methods=('POST', 'PUT', 'DELETE'), debug=False, **kwargs): """Try to obtain cached output. If fresh enough, raise HTTPError(304). If POST, PUT, or DELETE: * invalidates (deletes) any cached response for this resource * sets request.cached = False * sets request.cacheable = False else if a cached copy exists: * sets request.cached = True * sets request.cacheable = False * sets response.headers to the cached values * checks the cached Last-Modified response header against the current If-(Un)Modified-Since request headers; raises 304 if necessary. * sets response.status and response.body to the cached values * returns True otherwise: * sets request.cached = False * sets request.cacheable = True * returns False """ request = cherrypy.serving.request response = cherrypy.serving.response if not hasattr(cherrypy, '_cache'): # Make a process-wide Cache object. cherrypy._cache = kwargs.pop('cache_class', MemoryCache)() # Take all remaining kwargs and set them on the Cache object. for k, v in kwargs.items(): setattr(cherrypy._cache, k, v) cherrypy._cache.debug = debug # POST, PUT, DELETE should invalidate (delete) the cached copy. # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.10. if request.method in invalid_methods: if debug: cherrypy.log('request.method %r in invalid_methods %r' % (request.method, invalid_methods), 'TOOLS.CACHING') cherrypy._cache.delete() request.cached = False request.cacheable = False return False if 'no-cache' in [e.value for e in request.headers.elements('Pragma')]: request.cached = False request.cacheable = True return False cache_data = cherrypy._cache.get() request.cached = bool(cache_data) request.cacheable = not request.cached if request.cached: # Serve the cached copy. max_age = cherrypy._cache.delay for v in [e.value for e in request.headers.elements('Cache-Control')]: atoms = v.split('=', 1) directive = atoms.pop(0) if directive == 'max-age': if len(atoms) != 1 or not atoms[0].isdigit(): raise cherrypy.HTTPError( 400, 'Invalid Cache-Control header') max_age = int(atoms[0]) break elif directive == 'no-cache': if debug: cherrypy.log( 'Ignoring cache due to Cache-Control: no-cache', 'TOOLS.CACHING') request.cached = False request.cacheable = True return False if debug: cherrypy.log('Reading response from cache', 'TOOLS.CACHING') s, h, b, create_time = cache_data age = int(response.time - create_time) if (age > max_age): if debug: cherrypy.log('Ignoring cache due to age > %d' % max_age, 'TOOLS.CACHING') request.cached = False request.cacheable = True return False # Copy the response headers. See # https://github.com/cherrypy/cherrypy/issues/721. response.headers = rh = httputil.HeaderMap() for k in h: dict.__setitem__(rh, k, dict.__getitem__(h, k)) # Add the required Age header response.headers['Age'] = str(age) try: # Note that validate_since depends on a Last-Modified header; # this was put into the cached copy, and should have been # resurrected just above (response.headers = cache_data[1]). cptools.validate_since() except cherrypy.HTTPRedirect: x = sys.exc_info()[1] if x.status == 304: cherrypy._cache.tot_non_modified += 1 raise # serve it & get out from the request response.status = s response.body = b else: if debug: cherrypy.log('request is not cached', 'TOOLS.CACHING') return request.cached def tee_output(): """Tee response output to cache storage. Internal.""" # Used by CachingTool by attaching to request.hooks request = cherrypy.serving.request if 'no-store' in request.headers.values('Cache-Control'): return def tee(body): """Tee response.body into a list.""" if ('no-cache' in response.headers.values('Pragma') or 'no-store' in response.headers.values('Cache-Control')): for chunk in body: yield chunk return output = [] for chunk in body: output.append(chunk) yield chunk # save the cache data body = ntob('').join(output) cherrypy._cache.put((response.status, response.headers or {}, body, response.time), len(body)) response = cherrypy.serving.response response.body = tee(response.body) def expires(secs=0, force=False, debug=False): """Tool for influencing cache mechanisms using the 'Expires' header. secs Must be either an int or a datetime.timedelta, and indicates the number of seconds between response.time and when the response should expire. The 'Expires' header will be set to response.time + secs. If secs is zero, the 'Expires' header is set one year in the past, and the following "cache prevention" headers are also set: * Pragma: no-cache * Cache-Control': no-cache, must-revalidate force If False, the following headers are checked: * Etag * Last-Modified * Age * Expires If any are already present, none of the above response headers are set. """ response = cherrypy.serving.response headers = response.headers cacheable = False if not force: # some header names that indicate that the response can be cached for indicator in ('Etag', 'Last-Modified', 'Age', 'Expires'): if indicator in headers: cacheable = True break if not cacheable and not force: if debug: cherrypy.log('request is not cacheable', 'TOOLS.EXPIRES') else: if debug: cherrypy.log('request is cacheable', 'TOOLS.EXPIRES') if isinstance(secs, datetime.timedelta): secs = (86400 * secs.days) + secs.seconds if secs == 0: if force or ('Pragma' not in headers): headers['Pragma'] = 'no-cache' if cherrypy.serving.request.protocol >= (1, 1): if force or 'Cache-Control' not in headers: headers['Cache-Control'] = 'no-cache, must-revalidate' # Set an explicit Expires date in the past. expiry = httputil.HTTPDate(1169942400.0) else: expiry = httputil.HTTPDate(response.time + secs) if force or 'Expires' not in headers: headers['Expires'] = expiry SABnzbd-2.3.2/cherrypy/lib/covercp.py0000644000000000000000000002651713217005257015572 0ustar 00000000000000"""Code-coverage tools for CherryPy. To use this module, or the coverage tools in the test suite, you need to download 'coverage.py', either Gareth Rees' `original implementation `_ or Ned Batchelder's `enhanced version: `_ To turn on coverage tracing, use the following code:: cherrypy.engine.subscribe('start', covercp.start) DO NOT subscribe anything on the 'start_thread' channel, as previously recommended. Calling start once in the main thread should be sufficient to start coverage on all threads. Calling start again in each thread effectively clears any coverage data gathered up to that point. Run your code, then use the ``covercp.serve()`` function to browse the results in a web browser. If you run this module from the command line, it will call ``serve()`` for you. """ import re import sys import cgi import os import os.path import cherrypy from cherrypy._cpcompat import quote_plus localFile = os.path.join(os.path.dirname(__file__), 'coverage.cache') the_coverage = None try: from coverage import coverage the_coverage = coverage(data_file=localFile) def start(): the_coverage.start() except ImportError: # Setting the_coverage to None will raise errors # that need to be trapped downstream. the_coverage = None import warnings warnings.warn( 'No code coverage will be performed; ' 'coverage.py could not be imported.') def start(): pass start.priority = 20 TEMPLATE_MENU = """ CherryPy Coverage Menu

CherryPy Coverage

""" TEMPLATE_FORM = """
Show percentages
Hide files over %%
Exclude files matching

""" TEMPLATE_FRAMESET = """ CherryPy coverage data """ TEMPLATE_COVERAGE = """ Coverage for %(name)s

%(name)s

%(fullpath)s

Coverage: %(pc)s%%

""" TEMPLATE_LOC_COVERED = """ %s  %s \n""" TEMPLATE_LOC_NOT_COVERED = """ %s  %s \n""" TEMPLATE_LOC_EXCLUDED = """ %s  %s \n""" TEMPLATE_ITEM = ( "%s%s%s\n" ) def _percent(statements, missing): s = len(statements) e = s - len(missing) if s > 0: return int(round(100.0 * e / s)) return 0 def _show_branch(root, base, path, pct=0, showpct=False, exclude='', coverage=the_coverage): # Show the directory name and any of our children dirs = [k for k, v in root.items() if v] dirs.sort() for name in dirs: newpath = os.path.join(path, name) if newpath.lower().startswith(base): relpath = newpath[len(base):] yield '| ' * relpath.count(os.sep) yield ( "%s\n" % (newpath, quote_plus(exclude), name) ) for chunk in _show_branch( root[name], base, newpath, pct, showpct, exclude, coverage=coverage ): yield chunk # Now list the files if path.lower().startswith(base): relpath = path[len(base):] files = [k for k, v in root.items() if not v] files.sort() for name in files: newpath = os.path.join(path, name) pc_str = '' if showpct: try: _, statements, _, missing, _ = coverage.analysis2(newpath) except: # Yes, we really want to pass on all errors. pass else: pc = _percent(statements, missing) pc_str = ('%3d%% ' % pc).replace(' ', ' ') if pc < float(pct) or pc == -1: pc_str = "%s" % pc_str else: pc_str = "%s" % pc_str yield TEMPLATE_ITEM % ('| ' * (relpath.count(os.sep) + 1), pc_str, newpath, name) def _skip_file(path, exclude): if exclude: return bool(re.search(exclude, path)) def _graft(path, tree): d = tree p = path atoms = [] while True: p, tail = os.path.split(p) if not tail: break atoms.append(tail) atoms.append(p) if p != '/': atoms.append('/') atoms.reverse() for node in atoms: if node: d = d.setdefault(node, {}) def get_tree(base, exclude, coverage=the_coverage): """Return covered module names as a nested dict.""" tree = {} runs = coverage.data.executed_files() for path in runs: if not _skip_file(path, exclude) and not os.path.isdir(path): _graft(path, tree) return tree class CoverStats(object): def __init__(self, coverage, root=None): self.coverage = coverage if root is None: # Guess initial depth. Files outside this path will not be # reachable from the web interface. import cherrypy root = os.path.dirname(cherrypy.__file__) self.root = root @cherrypy.expose def index(self): return TEMPLATE_FRAMESET % self.root.lower() @cherrypy.expose def menu(self, base='/', pct='50', showpct='', exclude=r'python\d\.\d|test|tut\d|tutorial'): # The coverage module uses all-lower-case names. base = base.lower().rstrip(os.sep) yield TEMPLATE_MENU yield TEMPLATE_FORM % locals() # Start by showing links for parent paths yield "
" path = '' atoms = base.split(os.sep) atoms.pop() for atom in atoms: path += atom + os.sep yield ("%s %s" % (path, quote_plus(exclude), atom, os.sep)) yield '
' yield "
" # Then display the tree tree = get_tree(base, exclude, self.coverage) if not tree: yield '

No modules covered.

' else: for chunk in _show_branch(tree, base, '/', pct, showpct == 'checked', exclude, coverage=self.coverage): yield chunk yield '
' yield '' def annotated_file(self, filename, statements, excluded, missing): source = open(filename, 'r') buffer = [] for lineno, line in enumerate(source.readlines()): lineno += 1 line = line.strip('\n\r') empty_the_buffer = True if lineno in excluded: template = TEMPLATE_LOC_EXCLUDED elif lineno in missing: template = TEMPLATE_LOC_NOT_COVERED elif lineno in statements: template = TEMPLATE_LOC_COVERED else: empty_the_buffer = False buffer.append((lineno, line)) if empty_the_buffer: for lno, pastline in buffer: yield template % (lno, cgi.escape(pastline)) buffer = [] yield template % (lineno, cgi.escape(line)) @cherrypy.expose def report(self, name): filename, statements, excluded, missing, _ = self.coverage.analysis2( name) pc = _percent(statements, missing) yield TEMPLATE_COVERAGE % dict(name=os.path.basename(name), fullpath=name, pc=pc) yield '\n' for line in self.annotated_file(filename, statements, excluded, missing): yield line yield '
' yield '' yield '' def serve(path=localFile, port=8080, root=None): if coverage is None: raise ImportError('The coverage module could not be imported.') from coverage import coverage cov = coverage(data_file=path) cov.load() import cherrypy cherrypy.config.update({'server.socket_port': int(port), 'server.thread_pool': 10, 'environment': 'production', }) cherrypy.quickstart(CoverStats(cov, root)) if __name__ == '__main__': serve(*tuple(sys.argv[1:])) SABnzbd-2.3.2/cherrypy/lib/cpstats.py0000644000000000000000000005462413217005257015612 0ustar 00000000000000"""CPStats, a package for collecting and reporting on program statistics. Overview ======== Statistics about program operation are an invaluable monitoring and debugging tool. Unfortunately, the gathering and reporting of these critical values is usually ad-hoc. This package aims to add a centralized place for gathering statistical performance data, a structure for recording that data which provides for extrapolation of that data into more useful information, and a method of serving that data to both human investigators and monitoring software. Let's examine each of those in more detail. Data Gathering -------------- Just as Python's `logging` module provides a common importable for gathering and sending messages, performance statistics would benefit from a similar common mechanism, and one that does *not* require each package which wishes to collect stats to import a third-party module. Therefore, we choose to re-use the `logging` module by adding a `statistics` object to it. That `logging.statistics` object is a nested dict. It is not a custom class, because that would: 1. require libraries and applications to import a third-party module in order to participate 2. inhibit innovation in extrapolation approaches and in reporting tools, and 3. be slow. There are, however, some specifications regarding the structure of the dict.:: { +----"SQLAlchemy": { | "Inserts": 4389745, | "Inserts per Second": | lambda s: s["Inserts"] / (time() - s["Start"]), | C +---"Table Statistics": { | o | "widgets": {-----------+ N | l | "Rows": 1.3M, | Record a | l | "Inserts": 400, | m | e | },---------------------+ e | c | "froobles": { s | t | "Rows": 7845, p | i | "Inserts": 0, a | o | }, c | n +---}, e | "Slow Queries": | [{"Query": "SELECT * FROM widgets;", | "Processing Time": 47.840923343, | }, | ], +----}, } The `logging.statistics` dict has four levels. The topmost level is nothing more than a set of names to introduce modularity, usually along the lines of package names. If the SQLAlchemy project wanted to participate, for example, it might populate the item `logging.statistics['SQLAlchemy']`, whose value would be a second-layer dict we call a "namespace". Namespaces help multiple packages to avoid collisions over key names, and make reports easier to read, to boot. The maintainers of SQLAlchemy should feel free to use more than one namespace if needed (such as 'SQLAlchemy ORM'). Note that there are no case or other syntax constraints on the namespace names; they should be chosen to be maximally readable by humans (neither too short nor too long). Each namespace, then, is a dict of named statistical values, such as 'Requests/sec' or 'Uptime'. You should choose names which will look good on a report: spaces and capitalization are just fine. In addition to scalars, values in a namespace MAY be a (third-layer) dict, or a list, called a "collection". For example, the CherryPy :class:`StatsTool` keeps track of what each request is doing (or has most recently done) in a 'Requests' collection, where each key is a thread ID; each value in the subdict MUST be a fourth dict (whew!) of statistical data about each thread. We call each subdict in the collection a "record". Similarly, the :class:`StatsTool` also keeps a list of slow queries, where each record contains data about each slow query, in order. Values in a namespace or record may also be functions, which brings us to: Extrapolation ------------- The collection of statistical data needs to be fast, as close to unnoticeable as possible to the host program. That requires us to minimize I/O, for example, but in Python it also means we need to minimize function calls. So when you are designing your namespace and record values, try to insert the most basic scalar values you already have on hand. When it comes time to report on the gathered data, however, we usually have much more freedom in what we can calculate. Therefore, whenever reporting tools (like the provided :class:`StatsPage` CherryPy class) fetch the contents of `logging.statistics` for reporting, they first call `extrapolate_statistics` (passing the whole `statistics` dict as the only argument). This makes a deep copy of the statistics dict so that the reporting tool can both iterate over it and even change it without harming the original. But it also expands any functions in the dict by calling them. For example, you might have a 'Current Time' entry in the namespace with the value "lambda scope: time.time()". The "scope" parameter is the current namespace dict (or record, if we're currently expanding one of those instead), allowing you access to existing static entries. If you're truly evil, you can even modify more than one entry at a time. However, don't try to calculate an entry and then use its value in further extrapolations; the order in which the functions are called is not guaranteed. This can lead to a certain amount of duplicated work (or a redesign of your schema), but that's better than complicating the spec. After the whole thing has been extrapolated, it's time for: Reporting --------- The :class:`StatsPage` class grabs the `logging.statistics` dict, extrapolates it all, and then transforms it to HTML for easy viewing. Each namespace gets its own header and attribute table, plus an extra table for each collection. This is NOT part of the statistics specification; other tools can format how they like. You can control which columns are output and how they are formatted by updating StatsPage.formatting, which is a dict that mirrors the keys and nesting of `logging.statistics`. The difference is that, instead of data values, it has formatting values. Use None for a given key to indicate to the StatsPage that a given column should not be output. Use a string with formatting (such as '%.3f') to interpolate the value(s), or use a callable (such as lambda v: v.isoformat()) for more advanced formatting. Any entry which is not mentioned in the formatting dict is output unchanged. Monitoring ---------- Although the HTML output takes pains to assign unique id's to each with statistical data, you're probably better off fetching /cpstats/data, which outputs the whole (extrapolated) `logging.statistics` dict in JSON format. That is probably easier to parse, and doesn't have any formatting controls, so you get the "original" data in a consistently-serialized format. Note: there's no treatment yet for datetime objects. Try time.time() instead for now if you can. Nagios will probably thank you. Turning Collection Off ---------------------- It is recommended each namespace have an "Enabled" item which, if False, stops collection (but not reporting) of statistical data. Applications SHOULD provide controls to pause and resume collection by setting these entries to False or True, if present. Usage ===== To collect statistics on CherryPy applications:: from cherrypy.lib import cpstats appconfig['/']['tools.cpstats.on'] = True To collect statistics on your own code:: import logging # Initialize the repository if not hasattr(logging, 'statistics'): logging.statistics = {} # Initialize my namespace mystats = logging.statistics.setdefault('My Stuff', {}) # Initialize my namespace's scalars and collections mystats.update({ 'Enabled': True, 'Start Time': time.time(), 'Important Events': 0, 'Events/Second': lambda s: ( (s['Important Events'] / (time.time() - s['Start Time']))), }) ... for event in events: ... # Collect stats if mystats.get('Enabled', False): mystats['Important Events'] += 1 To report statistics:: root.cpstats = cpstats.StatsPage() To format statistics reports:: See 'Reporting', above. """ import logging import os import sys import threading import time import cherrypy from cherrypy._cpcompat import json # ------------------------------- Statistics -------------------------------- # if not hasattr(logging, 'statistics'): logging.statistics = {} def extrapolate_statistics(scope): """Return an extrapolated copy of the given scope.""" c = {} for k, v in list(scope.items()): if isinstance(v, dict): v = extrapolate_statistics(v) elif isinstance(v, (list, tuple)): v = [extrapolate_statistics(record) for record in v] elif hasattr(v, '__call__'): v = v(scope) c[k] = v return c # -------------------- CherryPy Applications Statistics --------------------- # appstats = logging.statistics.setdefault('CherryPy Applications', {}) appstats.update({ 'Enabled': True, 'Bytes Read/Request': lambda s: ( s['Total Requests'] and (s['Total Bytes Read'] / float(s['Total Requests'])) or 0.0 ), 'Bytes Read/Second': lambda s: s['Total Bytes Read'] / s['Uptime'](s), 'Bytes Written/Request': lambda s: ( s['Total Requests'] and (s['Total Bytes Written'] / float(s['Total Requests'])) or 0.0 ), 'Bytes Written/Second': lambda s: ( s['Total Bytes Written'] / s['Uptime'](s) ), 'Current Time': lambda s: time.time(), 'Current Requests': 0, 'Requests/Second': lambda s: float(s['Total Requests']) / s['Uptime'](s), 'Server Version': cherrypy.__version__, 'Start Time': time.time(), 'Total Bytes Read': 0, 'Total Bytes Written': 0, 'Total Requests': 0, 'Total Time': 0, 'Uptime': lambda s: time.time() - s['Start Time'], 'Requests': {}, }) proc_time = lambda s: time.time() - s['Start Time'] class ByteCountWrapper(object): """Wraps a file-like object, counting the number of bytes read.""" def __init__(self, rfile): self.rfile = rfile self.bytes_read = 0 def read(self, size=-1): data = self.rfile.read(size) self.bytes_read += len(data) return data def readline(self, size=-1): data = self.rfile.readline(size) self.bytes_read += len(data) return data def readlines(self, sizehint=0): # Shamelessly stolen from StringIO total = 0 lines = [] line = self.readline() while line: lines.append(line) total += len(line) if 0 < sizehint <= total: break line = self.readline() return lines def close(self): self.rfile.close() def __iter__(self): return self def next(self): data = self.rfile.next() self.bytes_read += len(data) return data average_uriset_time = lambda s: s['Count'] and (s['Sum'] / s['Count']) or 0 def _get_threading_ident(): if sys.version_info >= (3, 3): return threading.get_ident() return threading._get_ident() class StatsTool(cherrypy.Tool): """Record various information about the current request.""" def __init__(self): cherrypy.Tool.__init__(self, 'on_end_request', self.record_stop) def _setup(self): """Hook this tool into cherrypy.request. The standard CherryPy request object will automatically call this method when the tool is "turned on" in config. """ if appstats.get('Enabled', False): cherrypy.Tool._setup(self) self.record_start() def record_start(self): """Record the beginning of a request.""" request = cherrypy.serving.request if not hasattr(request.rfile, 'bytes_read'): request.rfile = ByteCountWrapper(request.rfile) request.body.fp = request.rfile r = request.remote appstats['Current Requests'] += 1 appstats['Total Requests'] += 1 appstats['Requests'][_get_threading_ident()] = { 'Bytes Read': None, 'Bytes Written': None, # Use a lambda so the ip gets updated by tools.proxy later 'Client': lambda s: '%s:%s' % (r.ip, r.port), 'End Time': None, 'Processing Time': proc_time, 'Request-Line': request.request_line, 'Response Status': None, 'Start Time': time.time(), } def record_stop( self, uriset=None, slow_queries=1.0, slow_queries_count=100, debug=False, **kwargs): """Record the end of a request.""" resp = cherrypy.serving.response w = appstats['Requests'][_get_threading_ident()] r = cherrypy.request.rfile.bytes_read w['Bytes Read'] = r appstats['Total Bytes Read'] += r if resp.stream: w['Bytes Written'] = 'chunked' else: cl = int(resp.headers.get('Content-Length', 0)) w['Bytes Written'] = cl appstats['Total Bytes Written'] += cl w['Response Status'] = getattr( resp, 'output_status', None) or resp.status w['End Time'] = time.time() p = w['End Time'] - w['Start Time'] w['Processing Time'] = p appstats['Total Time'] += p appstats['Current Requests'] -= 1 if debug: cherrypy.log('Stats recorded: %s' % repr(w), 'TOOLS.CPSTATS') if uriset: rs = appstats.setdefault('URI Set Tracking', {}) r = rs.setdefault(uriset, { 'Min': None, 'Max': None, 'Count': 0, 'Sum': 0, 'Avg': average_uriset_time}) if r['Min'] is None or p < r['Min']: r['Min'] = p if r['Max'] is None or p > r['Max']: r['Max'] = p r['Count'] += 1 r['Sum'] += p if slow_queries and p > slow_queries: sq = appstats.setdefault('Slow Queries', []) sq.append(w.copy()) if len(sq) > slow_queries_count: sq.pop(0) cherrypy.tools.cpstats = StatsTool() # ---------------------- CherryPy Statistics Reporting ---------------------- # thisdir = os.path.abspath(os.path.dirname(__file__)) missing = object() locale_date = lambda v: time.strftime('%c', time.gmtime(v)) iso_format = lambda v: time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(v)) def pause_resume(ns): def _pause_resume(enabled): pause_disabled = '' resume_disabled = '' if enabled: resume_disabled = 'disabled="disabled" ' else: pause_disabled = 'disabled="disabled" ' return """
""" % (ns, pause_disabled, ns, resume_disabled) return _pause_resume class StatsPage(object): formatting = { 'CherryPy Applications': { 'Enabled': pause_resume('CherryPy Applications'), 'Bytes Read/Request': '%.3f', 'Bytes Read/Second': '%.3f', 'Bytes Written/Request': '%.3f', 'Bytes Written/Second': '%.3f', 'Current Time': iso_format, 'Requests/Second': '%.3f', 'Start Time': iso_format, 'Total Time': '%.3f', 'Uptime': '%.3f', 'Slow Queries': { 'End Time': None, 'Processing Time': '%.3f', 'Start Time': iso_format, }, 'URI Set Tracking': { 'Avg': '%.3f', 'Max': '%.3f', 'Min': '%.3f', 'Sum': '%.3f', }, 'Requests': { 'Bytes Read': '%s', 'Bytes Written': '%s', 'End Time': None, 'Processing Time': '%.3f', 'Start Time': None, }, }, 'CherryPy WSGIServer': { 'Enabled': pause_resume('CherryPy WSGIServer'), 'Connections/second': '%.3f', 'Start time': iso_format, }, } @cherrypy.expose def index(self): # Transform the raw data into pretty output for HTML yield """ Statistics """ for title, scalars, collections in self.get_namespaces(): yield """

%s

""" % title for i, (key, value) in enumerate(scalars): colnum = i % 3 if colnum == 0: yield """ """ yield ( """ """ % vars() ) if colnum == 2: yield """ """ if colnum == 0: yield """ """ elif colnum == 1: yield """ """ yield """
%(key)s%(value)s
""" for subtitle, headers, subrows in collections: yield """

%s

""" % subtitle for key in headers: yield """ """ % key yield """ """ for subrow in subrows: yield """ """ for value in subrow: yield """ """ % value yield """ """ yield """
%s
%s
""" yield """ """ def get_namespaces(self): """Yield (title, scalars, collections) for each namespace.""" s = extrapolate_statistics(logging.statistics) for title, ns in sorted(s.items()): scalars = [] collections = [] ns_fmt = self.formatting.get(title, {}) for k, v in sorted(ns.items()): fmt = ns_fmt.get(k, {}) if isinstance(v, dict): headers, subrows = self.get_dict_collection(v, fmt) collections.append((k, ['ID'] + headers, subrows)) elif isinstance(v, (list, tuple)): headers, subrows = self.get_list_collection(v, fmt) collections.append((k, headers, subrows)) else: format = ns_fmt.get(k, missing) if format is None: # Don't output this column. continue if hasattr(format, '__call__'): v = format(v) elif format is not missing: v = format % v scalars.append((k, v)) yield title, scalars, collections def get_dict_collection(self, v, formatting): """Return ([headers], [rows]) for the given collection.""" # E.g., the 'Requests' dict. headers = [] try: # python2 vals = v.itervalues() except AttributeError: # python3 vals = v.values() for record in vals: for k3 in record: format = formatting.get(k3, missing) if format is None: # Don't output this column. continue if k3 not in headers: headers.append(k3) headers.sort() subrows = [] for k2, record in sorted(v.items()): subrow = [k2] for k3 in headers: v3 = record.get(k3, '') format = formatting.get(k3, missing) if format is None: # Don't output this column. continue if hasattr(format, '__call__'): v3 = format(v3) elif format is not missing: v3 = format % v3 subrow.append(v3) subrows.append(subrow) return headers, subrows def get_list_collection(self, v, formatting): """Return ([headers], [subrows]) for the given collection.""" # E.g., the 'Slow Queries' list. headers = [] for record in v: for k3 in record: format = formatting.get(k3, missing) if format is None: # Don't output this column. continue if k3 not in headers: headers.append(k3) headers.sort() subrows = [] for record in v: subrow = [] for k3 in headers: v3 = record.get(k3, '') format = formatting.get(k3, missing) if format is None: # Don't output this column. continue if hasattr(format, '__call__'): v3 = format(v3) elif format is not missing: v3 = format % v3 subrow.append(v3) subrows.append(subrow) return headers, subrows if json is not None: @cherrypy.expose def data(self): s = extrapolate_statistics(logging.statistics) cherrypy.response.headers['Content-Type'] = 'application/json' return json.dumps(s, sort_keys=True, indent=4) @cherrypy.expose def pause(self, namespace): logging.statistics.get(namespace, {})['Enabled'] = False raise cherrypy.HTTPRedirect('./') pause.cp_config = {'tools.allow.on': True, 'tools.allow.methods': ['POST']} @cherrypy.expose def resume(self, namespace): logging.statistics.get(namespace, {})['Enabled'] = True raise cherrypy.HTTPRedirect('./') resume.cp_config = {'tools.allow.on': True, 'tools.allow.methods': ['POST']} SABnzbd-2.3.2/cherrypy/lib/cptools.py0000644000000000000000000005631513217005257015613 0ustar 00000000000000"""Functions for builtin CherryPy tools.""" import logging import re from hashlib import md5 import six import cherrypy from cherrypy._cpcompat import text_or_bytes from cherrypy.lib import httputil as _httputil from cherrypy.lib import is_iterator # Conditional HTTP request support # def validate_etags(autotags=False, debug=False): """Validate the current ETag against If-Match, If-None-Match headers. If autotags is True, an ETag response-header value will be provided from an MD5 hash of the response body (unless some other code has already provided an ETag header). If False (the default), the ETag will not be automatic. WARNING: the autotags feature is not designed for URL's which allow methods other than GET. For example, if a POST to the same URL returns no content, the automatic ETag will be incorrect, breaking a fundamental use for entity tags in a possibly destructive fashion. Likewise, if you raise 304 Not Modified, the response body will be empty, the ETag hash will be incorrect, and your application will break. See :rfc:`2616` Section 14.24. """ response = cherrypy.serving.response # Guard against being run twice. if hasattr(response, 'ETag'): return status, reason, msg = _httputil.valid_status(response.status) etag = response.headers.get('ETag') # Automatic ETag generation. See warning in docstring. if etag: if debug: cherrypy.log('ETag already set: %s' % etag, 'TOOLS.ETAGS') elif not autotags: if debug: cherrypy.log('Autotags off', 'TOOLS.ETAGS') elif status != 200: if debug: cherrypy.log('Status not 200', 'TOOLS.ETAGS') else: etag = response.collapse_body() etag = '"%s"' % md5(etag).hexdigest() if debug: cherrypy.log('Setting ETag: %s' % etag, 'TOOLS.ETAGS') response.headers['ETag'] = etag response.ETag = etag # "If the request would, without the If-Match header field, result in # anything other than a 2xx or 412 status, then the If-Match header # MUST be ignored." if debug: cherrypy.log('Status: %s' % status, 'TOOLS.ETAGS') if status >= 200 and status <= 299: request = cherrypy.serving.request conditions = request.headers.elements('If-Match') or [] conditions = [str(x) for x in conditions] if debug: cherrypy.log('If-Match conditions: %s' % repr(conditions), 'TOOLS.ETAGS') if conditions and not (conditions == ['*'] or etag in conditions): raise cherrypy.HTTPError(412, 'If-Match failed: ETag %r did ' 'not match %r' % (etag, conditions)) conditions = request.headers.elements('If-None-Match') or [] conditions = [str(x) for x in conditions] if debug: cherrypy.log('If-None-Match conditions: %s' % repr(conditions), 'TOOLS.ETAGS') if conditions == ['*'] or etag in conditions: if debug: cherrypy.log('request.method: %s' % request.method, 'TOOLS.ETAGS') if request.method in ('GET', 'HEAD'): raise cherrypy.HTTPRedirect([], 304) else: raise cherrypy.HTTPError(412, 'If-None-Match failed: ETag %r ' 'matched %r' % (etag, conditions)) def validate_since(): """Validate the current Last-Modified against If-Modified-Since headers. If no code has set the Last-Modified response header, then no validation will be performed. """ response = cherrypy.serving.response lastmod = response.headers.get('Last-Modified') if lastmod: status, reason, msg = _httputil.valid_status(response.status) request = cherrypy.serving.request since = request.headers.get('If-Unmodified-Since') if since and since != lastmod: if (status >= 200 and status <= 299) or status == 412: raise cherrypy.HTTPError(412) since = request.headers.get('If-Modified-Since') if since and since == lastmod: if (status >= 200 and status <= 299) or status == 304: if request.method in ('GET', 'HEAD'): raise cherrypy.HTTPRedirect([], 304) else: raise cherrypy.HTTPError(412) # Tool code # def allow(methods=None, debug=False): """Raise 405 if request.method not in methods (default ['GET', 'HEAD']). The given methods are case-insensitive, and may be in any order. If only one method is allowed, you may supply a single string; if more than one, supply a list of strings. Regardless of whether the current method is allowed or not, this also emits an 'Allow' response header, containing the given methods. """ if not isinstance(methods, (tuple, list)): methods = [methods] methods = [m.upper() for m in methods if m] if not methods: methods = ['GET', 'HEAD'] elif 'GET' in methods and 'HEAD' not in methods: methods.append('HEAD') cherrypy.response.headers['Allow'] = ', '.join(methods) if cherrypy.request.method not in methods: if debug: cherrypy.log('request.method %r not in methods %r' % (cherrypy.request.method, methods), 'TOOLS.ALLOW') raise cherrypy.HTTPError(405) else: if debug: cherrypy.log('request.method %r in methods %r' % (cherrypy.request.method, methods), 'TOOLS.ALLOW') def proxy(base=None, local='X-Forwarded-Host', remote='X-Forwarded-For', scheme='X-Forwarded-Proto', debug=False): """Change the base URL (scheme://host[:port][/path]). For running a CP server behind Apache, lighttpd, or other HTTP server. For Apache and lighttpd, you should leave the 'local' argument at the default value of 'X-Forwarded-Host'. For Squid, you probably want to set tools.proxy.local = 'Origin'. If you want the new request.base to include path info (not just the host), you must explicitly set base to the full base path, and ALSO set 'local' to '', so that the X-Forwarded-Host request header (which never includes path info) does not override it. Regardless, the value for 'base' MUST NOT end in a slash. cherrypy.request.remote.ip (the IP address of the client) will be rewritten if the header specified by the 'remote' arg is valid. By default, 'remote' is set to 'X-Forwarded-For'. If you do not want to rewrite remote.ip, set the 'remote' arg to an empty string. """ request = cherrypy.serving.request if scheme: s = request.headers.get(scheme, None) if debug: cherrypy.log('Testing scheme %r:%r' % (scheme, s), 'TOOLS.PROXY') if s == 'on' and 'ssl' in scheme.lower(): # This handles e.g. webfaction's 'X-Forwarded-Ssl: on' header scheme = 'https' else: # This is for lighttpd/pound/Mongrel's 'X-Forwarded-Proto: https' scheme = s if not scheme: scheme = request.base[:request.base.find('://')] if local: lbase = request.headers.get(local, None) if debug: cherrypy.log('Testing local %r:%r' % (local, lbase), 'TOOLS.PROXY') if lbase is not None: base = lbase.split(',')[0] if not base: base = request.headers.get('Host', '127.0.0.1') port = request.local.port if port != 80: base += ':%s' % port if base.find('://') == -1: # add http:// or https:// if needed base = scheme + '://' + base request.base = base if remote: xff = request.headers.get(remote) if debug: cherrypy.log('Testing remote %r:%r' % (remote, xff), 'TOOLS.PROXY') if xff: if remote == 'X-Forwarded-For': # Bug #1268 xff = xff.split(',')[0].strip() request.remote.ip = xff def ignore_headers(headers=('Range',), debug=False): """Delete request headers whose field names are included in 'headers'. This is a useful tool for working behind certain HTTP servers; for example, Apache duplicates the work that CP does for 'Range' headers, and will doubly-truncate the response. """ request = cherrypy.serving.request for name in headers: if name in request.headers: if debug: cherrypy.log('Ignoring request header %r' % name, 'TOOLS.IGNORE_HEADERS') del request.headers[name] def response_headers(headers=None, debug=False): """Set headers on the response.""" if debug: cherrypy.log('Setting response headers: %s' % repr(headers), 'TOOLS.RESPONSE_HEADERS') for name, value in (headers or []): cherrypy.serving.response.headers[name] = value response_headers.failsafe = True def referer(pattern, accept=True, accept_missing=False, error=403, message='Forbidden Referer header.', debug=False): """Raise HTTPError if Referer header does/does not match the given pattern. pattern A regular expression pattern to test against the Referer. accept If True, the Referer must match the pattern; if False, the Referer must NOT match the pattern. accept_missing If True, permit requests with no Referer header. error The HTTP error code to return to the client on failure. message A string to include in the response body on failure. """ try: ref = cherrypy.serving.request.headers['Referer'] match = bool(re.match(pattern, ref)) if debug: cherrypy.log('Referer %r matches %r' % (ref, pattern), 'TOOLS.REFERER') if accept == match: return except KeyError: if debug: cherrypy.log('No Referer header', 'TOOLS.REFERER') if accept_missing: return raise cherrypy.HTTPError(error, message) class SessionAuth(object): """Assert that the user is logged in.""" session_key = 'username' debug = False def check_username_and_password(self, username, password): pass def anonymous(self): """Provide a temporary user name for anonymous users.""" pass def on_login(self, username): pass def on_logout(self, username): pass def on_check(self, username): pass def login_screen(self, from_page='..', username='', error_msg='', **kwargs): return (six.text_type(""" Message: %(error_msg)s
Login:
Password:

""") % vars()).encode('utf-8') def do_login(self, username, password, from_page='..', **kwargs): """Login. May raise redirect, or return True if request handled.""" response = cherrypy.serving.response error_msg = self.check_username_and_password(username, password) if error_msg: body = self.login_screen(from_page, username, error_msg) response.body = body if 'Content-Length' in response.headers: # Delete Content-Length header so finalize() recalcs it. del response.headers['Content-Length'] return True else: cherrypy.serving.request.login = username cherrypy.session[self.session_key] = username self.on_login(username) raise cherrypy.HTTPRedirect(from_page or '/') def do_logout(self, from_page='..', **kwargs): """Logout. May raise redirect, or return True if request handled.""" sess = cherrypy.session username = sess.get(self.session_key) sess[self.session_key] = None if username: cherrypy.serving.request.login = None self.on_logout(username) raise cherrypy.HTTPRedirect(from_page) def do_check(self): """Assert username. Raise redirect, or return True if request handled. """ sess = cherrypy.session request = cherrypy.serving.request response = cherrypy.serving.response username = sess.get(self.session_key) if not username: sess[self.session_key] = username = self.anonymous() self._debug_message('No session[username], trying anonymous') if not username: url = cherrypy.url(qs=request.query_string) self._debug_message( 'No username, routing to login_screen with from_page %(url)r', locals(), ) response.body = self.login_screen(url) if 'Content-Length' in response.headers: # Delete Content-Length header so finalize() recalcs it. del response.headers['Content-Length'] return True self._debug_message('Setting request.login to %(username)r', locals()) request.login = username self.on_check(username) def _debug_message(self, template, context={}): if not self.debug: return cherrypy.log(template % context, 'TOOLS.SESSAUTH') def run(self): request = cherrypy.serving.request response = cherrypy.serving.response path = request.path_info if path.endswith('login_screen'): self._debug_message('routing %(path)r to login_screen', locals()) response.body = self.login_screen() return True elif path.endswith('do_login'): if request.method != 'POST': response.headers['Allow'] = 'POST' self._debug_message('do_login requires POST') raise cherrypy.HTTPError(405) self._debug_message('routing %(path)r to do_login', locals()) return self.do_login(**request.params) elif path.endswith('do_logout'): if request.method != 'POST': response.headers['Allow'] = 'POST' raise cherrypy.HTTPError(405) self._debug_message('routing %(path)r to do_logout', locals()) return self.do_logout(**request.params) else: self._debug_message('No special path, running do_check') return self.do_check() def session_auth(**kwargs): sa = SessionAuth() for k, v in kwargs.items(): setattr(sa, k, v) return sa.run() session_auth.__doc__ = """Session authentication hook. Any attribute of the SessionAuth class may be overridden via a keyword arg to this function: """ + '\n'.join(['%s: %s' % (k, type(getattr(SessionAuth, k)).__name__) for k in dir(SessionAuth) if not k.startswith('__')]) def log_traceback(severity=logging.ERROR, debug=False): """Write the last error's traceback to the cherrypy error log.""" cherrypy.log('', 'HTTP', severity=severity, traceback=True) def log_request_headers(debug=False): """Write request headers to the cherrypy error log.""" h = [' %s: %s' % (k, v) for k, v in cherrypy.serving.request.header_list] cherrypy.log('\nRequest Headers:\n' + '\n'.join(h), 'HTTP') def log_hooks(debug=False): """Write request.hooks to the cherrypy error log.""" request = cherrypy.serving.request msg = [] # Sort by the standard points if possible. from cherrypy import _cprequest points = _cprequest.hookpoints for k in request.hooks.keys(): if k not in points: points.append(k) for k in points: msg.append(' %s:' % k) v = request.hooks.get(k, []) v.sort() for h in v: msg.append(' %r' % h) cherrypy.log('\nRequest Hooks for ' + cherrypy.url() + ':\n' + '\n'.join(msg), 'HTTP') def redirect(url='', internal=True, debug=False): """Raise InternalRedirect or HTTPRedirect to the given url.""" if debug: cherrypy.log('Redirecting %sto: %s' % ({True: 'internal ', False: ''}[internal], url), 'TOOLS.REDIRECT') if internal: raise cherrypy.InternalRedirect(url) else: raise cherrypy.HTTPRedirect(url) def trailing_slash(missing=True, extra=False, status=None, debug=False): """Redirect if path_info has (missing|extra) trailing slash.""" request = cherrypy.serving.request pi = request.path_info if debug: cherrypy.log('is_index: %r, missing: %r, extra: %r, path_info: %r' % (request.is_index, missing, extra, pi), 'TOOLS.TRAILING_SLASH') if request.is_index is True: if missing: if not pi.endswith('/'): new_url = cherrypy.url(pi + '/', request.query_string) raise cherrypy.HTTPRedirect(new_url, status=status or 301) elif request.is_index is False: if extra: # If pi == '/', don't redirect to ''! if pi.endswith('/') and pi != '/': new_url = cherrypy.url(pi[:-1], request.query_string) raise cherrypy.HTTPRedirect(new_url, status=status or 301) def flatten(debug=False): """Wrap response.body in a generator that recursively iterates over body. This allows cherrypy.response.body to consist of 'nested generators'; that is, a set of generators that yield generators. """ def flattener(input): numchunks = 0 for x in input: if not is_iterator(x): numchunks += 1 yield x else: for y in flattener(x): numchunks += 1 yield y if debug: cherrypy.log('Flattened %d chunks' % numchunks, 'TOOLS.FLATTEN') response = cherrypy.serving.response response.body = flattener(response.body) def accept(media=None, debug=False): """Return the client's preferred media-type (from the given Content-Types). If 'media' is None (the default), no test will be performed. If 'media' is provided, it should be the Content-Type value (as a string) or values (as a list or tuple of strings) which the current resource can emit. The client's acceptable media ranges (as declared in the Accept request header) will be matched in order to these Content-Type values; the first such string is returned. That is, the return value will always be one of the strings provided in the 'media' arg (or None if 'media' is None). If no match is found, then HTTPError 406 (Not Acceptable) is raised. Note that most web browsers send */* as a (low-quality) acceptable media range, which should match any Content-Type. In addition, "...if no Accept header field is present, then it is assumed that the client accepts all media types." Matching types are checked in order of client preference first, and then in the order of the given 'media' values. Note that this function does not honor accept-params (other than "q"). """ if not media: return if isinstance(media, text_or_bytes): media = [media] request = cherrypy.serving.request # Parse the Accept request header, and try to match one # of the requested media-ranges (in order of preference). ranges = request.headers.elements('Accept') if not ranges: # Any media type is acceptable. if debug: cherrypy.log('No Accept header elements', 'TOOLS.ACCEPT') return media[0] else: # Note that 'ranges' is sorted in order of preference for element in ranges: if element.qvalue > 0: if element.value == '*/*': # Matches any type or subtype if debug: cherrypy.log('Match due to */*', 'TOOLS.ACCEPT') return media[0] elif element.value.endswith('/*'): # Matches any subtype mtype = element.value[:-1] # Keep the slash for m in media: if m.startswith(mtype): if debug: cherrypy.log('Match due to %s' % element.value, 'TOOLS.ACCEPT') return m else: # Matches exact value if element.value in media: if debug: cherrypy.log('Match due to %s' % element.value, 'TOOLS.ACCEPT') return element.value # No suitable media-range found. ah = request.headers.get('Accept') if ah is None: msg = 'Your client did not send an Accept header.' else: msg = 'Your client sent this Accept header: %s.' % ah msg += (' But this resource only emits these media types: %s.' % ', '.join(media)) raise cherrypy.HTTPError(406, msg) class MonitoredHeaderMap(_httputil.HeaderMap): def __init__(self): self.accessed_headers = set() def __getitem__(self, key): self.accessed_headers.add(key) return _httputil.HeaderMap.__getitem__(self, key) def __contains__(self, key): self.accessed_headers.add(key) return _httputil.HeaderMap.__contains__(self, key) def get(self, key, default=None): self.accessed_headers.add(key) return _httputil.HeaderMap.get(self, key, default=default) if hasattr({}, 'has_key'): # Python 2 def has_key(self, key): self.accessed_headers.add(key) return _httputil.HeaderMap.has_key(self, key) def autovary(ignore=None, debug=False): """Auto-populate the Vary response header based on request.header access. """ request = cherrypy.serving.request req_h = request.headers request.headers = MonitoredHeaderMap() request.headers.update(req_h) if ignore is None: ignore = set(['Content-Disposition', 'Content-Length', 'Content-Type']) def set_response_header(): resp_h = cherrypy.serving.response.headers v = set([e.value for e in resp_h.elements('Vary')]) if debug: cherrypy.log( 'Accessed headers: %s' % request.headers.accessed_headers, 'TOOLS.AUTOVARY') v = v.union(request.headers.accessed_headers) v = v.difference(ignore) v = list(v) v.sort() resp_h['Vary'] = ', '.join(v) request.hooks.attach('before_finalize', set_response_header, 95) def convert_params(exception=ValueError, error=400): """Convert request params based on function annotations, with error handling. exception Exception class to catch. status The HTTP error code to return to the client on failure. """ request = cherrypy.serving.request types = request.handler.callable.__annotations__ with cherrypy.HTTPError.handle(exception, error): for key in set(types).intersection(request.params): request.params[key] = types[key](request.params[key]) SABnzbd-2.3.2/cherrypy/lib/encoding.py0000644000000000000000000003756013217005257015717 0ustar 00000000000000import struct import time import io import six import cherrypy from cherrypy._cpcompat import text_or_bytes, ntob from cherrypy.lib import file_generator from cherrypy.lib import is_closable_iterator from cherrypy.lib import set_vary_header def decode(encoding=None, default_encoding='utf-8'): """Replace or extend the list of charsets used to decode a request entity. Either argument may be a single string or a list of strings. encoding If not None, restricts the set of charsets attempted while decoding a request entity to the given set (even if a different charset is given in the Content-Type request header). default_encoding Only in effect if the 'encoding' argument is not given. If given, the set of charsets attempted while decoding a request entity is *extended* with the given value(s). """ body = cherrypy.request.body if encoding is not None: if not isinstance(encoding, list): encoding = [encoding] body.attempt_charsets = encoding elif default_encoding: if not isinstance(default_encoding, list): default_encoding = [default_encoding] body.attempt_charsets = body.attempt_charsets + default_encoding class UTF8StreamEncoder: def __init__(self, iterator): self._iterator = iterator def __iter__(self): return self def next(self): return self.__next__() def __next__(self): res = next(self._iterator) if isinstance(res, six.text_type): res = res.encode('utf-8') return res def close(self): if is_closable_iterator(self._iterator): self._iterator.close() def __getattr__(self, attr): if attr.startswith('__'): raise AttributeError(self, attr) return getattr(self._iterator, attr) class ResponseEncoder: default_encoding = 'utf-8' failmsg = 'Response body could not be encoded with %r.' encoding = None errors = 'strict' text_only = True add_charset = True debug = False def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) self.attempted_charsets = set() request = cherrypy.serving.request if request.handler is not None: # Replace request.handler with self if self.debug: cherrypy.log('Replacing request.handler', 'TOOLS.ENCODE') self.oldhandler = request.handler request.handler = self def encode_stream(self, encoding): """Encode a streaming response body. Use a generator wrapper, and just pray it works as the stream is being written out. """ if encoding in self.attempted_charsets: return False self.attempted_charsets.add(encoding) def encoder(body): for chunk in body: if isinstance(chunk, six.text_type): chunk = chunk.encode(encoding, self.errors) yield chunk self.body = encoder(self.body) return True def encode_string(self, encoding): """Encode a buffered response body.""" if encoding in self.attempted_charsets: return False self.attempted_charsets.add(encoding) body = [] for chunk in self.body: if isinstance(chunk, six.text_type): try: chunk = chunk.encode(encoding, self.errors) except (LookupError, UnicodeError): return False body.append(chunk) self.body = body return True def find_acceptable_charset(self): request = cherrypy.serving.request response = cherrypy.serving.response if self.debug: cherrypy.log('response.stream %r' % response.stream, 'TOOLS.ENCODE') if response.stream: encoder = self.encode_stream else: encoder = self.encode_string if 'Content-Length' in response.headers: # Delete Content-Length header so finalize() recalcs it. # Encoded strings may be of different lengths from their # unicode equivalents, and even from each other. For example: # >>> t = u"\u7007\u3040" # >>> len(t) # 2 # >>> len(t.encode("UTF-8")) # 6 # >>> len(t.encode("utf7")) # 8 del response.headers['Content-Length'] # Parse the Accept-Charset request header, and try to provide one # of the requested charsets (in order of user preference). encs = request.headers.elements('Accept-Charset') charsets = [enc.value.lower() for enc in encs] if self.debug: cherrypy.log('charsets %s' % repr(charsets), 'TOOLS.ENCODE') if self.encoding is not None: # If specified, force this encoding to be used, or fail. encoding = self.encoding.lower() if self.debug: cherrypy.log('Specified encoding %r' % encoding, 'TOOLS.ENCODE') if (not charsets) or '*' in charsets or encoding in charsets: if self.debug: cherrypy.log('Attempting encoding %r' % encoding, 'TOOLS.ENCODE') if encoder(encoding): return encoding else: if not encs: if self.debug: cherrypy.log('Attempting default encoding %r' % self.default_encoding, 'TOOLS.ENCODE') # Any character-set is acceptable. if encoder(self.default_encoding): return self.default_encoding else: raise cherrypy.HTTPError(500, self.failmsg % self.default_encoding) else: for element in encs: if element.qvalue > 0: if element.value == '*': # Matches any charset. Try our default. if self.debug: cherrypy.log('Attempting default encoding due ' 'to %r' % element, 'TOOLS.ENCODE') if encoder(self.default_encoding): return self.default_encoding else: encoding = element.value if self.debug: cherrypy.log('Attempting encoding %s (qvalue >' '0)' % element, 'TOOLS.ENCODE') if encoder(encoding): return encoding if '*' not in charsets: # If no "*" is present in an Accept-Charset field, then all # character sets not explicitly mentioned get a quality # value of 0, except for ISO-8859-1, which gets a quality # value of 1 if not explicitly mentioned. iso = 'iso-8859-1' if iso not in charsets: if self.debug: cherrypy.log('Attempting ISO-8859-1 encoding', 'TOOLS.ENCODE') if encoder(iso): return iso # No suitable encoding found. ac = request.headers.get('Accept-Charset') if ac is None: msg = 'Your client did not send an Accept-Charset header.' else: msg = 'Your client sent this Accept-Charset header: %s.' % ac _charsets = ', '.join(sorted(self.attempted_charsets)) msg += ' We tried these charsets: %s.' % (_charsets,) raise cherrypy.HTTPError(406, msg) def __call__(self, *args, **kwargs): response = cherrypy.serving.response self.body = self.oldhandler(*args, **kwargs) if isinstance(self.body, text_or_bytes): # strings get wrapped in a list because iterating over a single # item list is much faster than iterating over every character # in a long string. if self.body: self.body = [self.body] else: # [''] doesn't evaluate to False, so replace it with []. self.body = [] elif hasattr(self.body, 'read'): self.body = file_generator(self.body) elif self.body is None: self.body = [] ct = response.headers.elements('Content-Type') if self.debug: cherrypy.log('Content-Type: %r' % [str(h) for h in ct], 'TOOLS.ENCODE') if ct and self.add_charset: ct = ct[0] if self.text_only: if ct.value.lower().startswith('text/'): if self.debug: cherrypy.log( 'Content-Type %s starts with "text/"' % ct, 'TOOLS.ENCODE') do_find = True else: if self.debug: cherrypy.log('Not finding because Content-Type %s ' 'does not start with "text/"' % ct, 'TOOLS.ENCODE') do_find = False else: if self.debug: cherrypy.log('Finding because not text_only', 'TOOLS.ENCODE') do_find = True if do_find: # Set "charset=..." param on response Content-Type header ct.params['charset'] = self.find_acceptable_charset() if self.debug: cherrypy.log('Setting Content-Type %s' % ct, 'TOOLS.ENCODE') response.headers['Content-Type'] = str(ct) return self.body # GZIP def compress(body, compress_level): """Compress 'body' at the given compress_level.""" import zlib # See http://www.gzip.org/zlib/rfc-gzip.html yield ntob('\x1f\x8b') # ID1 and ID2: gzip marker yield ntob('\x08') # CM: compression method yield ntob('\x00') # FLG: none set # MTIME: 4 bytes yield struct.pack(' 0 is present * The 'identity' value is given with a qvalue > 0. """ request = cherrypy.serving.request response = cherrypy.serving.response set_vary_header(response, 'Accept-Encoding') if not response.body: # Response body is empty (might be a 304 for instance) if debug: cherrypy.log('No response body', context='TOOLS.GZIP') return # If returning cached content (which should already have been gzipped), # don't re-zip. if getattr(request, 'cached', False): if debug: cherrypy.log('Not gzipping cached response', context='TOOLS.GZIP') return acceptable = request.headers.elements('Accept-Encoding') if not acceptable: # If no Accept-Encoding field is present in a request, # the server MAY assume that the client will accept any # content coding. In this case, if "identity" is one of # the available content-codings, then the server SHOULD use # the "identity" content-coding, unless it has additional # information that a different content-coding is meaningful # to the client. if debug: cherrypy.log('No Accept-Encoding', context='TOOLS.GZIP') return ct = response.headers.get('Content-Type', '').split(';')[0] for coding in acceptable: if coding.value == 'identity' and coding.qvalue != 0: if debug: cherrypy.log('Non-zero identity qvalue: %s' % coding, context='TOOLS.GZIP') return if coding.value in ('gzip', 'x-gzip'): if coding.qvalue == 0: if debug: cherrypy.log('Zero gzip qvalue: %s' % coding, context='TOOLS.GZIP') return if ct not in mime_types: # If the list of provided mime-types contains tokens # such as 'text/*' or 'application/*+xml', # we go through them and find the most appropriate one # based on the given content-type. # The pattern matching is only caring about the most # common cases, as stated above, and doesn't support # for extra parameters. found = False if '/' in ct: ct_media_type, ct_sub_type = ct.split('/') for mime_type in mime_types: if '/' in mime_type: media_type, sub_type = mime_type.split('/') if ct_media_type == media_type: if sub_type == '*': found = True break elif '+' in sub_type and '+' in ct_sub_type: ct_left, ct_right = ct_sub_type.split('+') left, right = sub_type.split('+') if left == '*' and ct_right == right: found = True break if not found: if debug: cherrypy.log('Content-Type %s not in mime_types %r' % (ct, mime_types), context='TOOLS.GZIP') return if debug: cherrypy.log('Gzipping', context='TOOLS.GZIP') # Return a generator that compresses the page response.headers['Content-Encoding'] = 'gzip' response.body = compress(response.body, compress_level) if 'Content-Length' in response.headers: # Delete Content-Length header so finalize() recalcs it. del response.headers['Content-Length'] return if debug: cherrypy.log('No acceptable encoding found.', context='GZIP') cherrypy.HTTPError(406, 'identity, gzip').set_response() SABnzbd-2.3.2/cherrypy/lib/gctools.py0000644000000000000000000001626013217005257015575 0ustar 00000000000000import gc import inspect import sys import time try: import objgraph except ImportError: objgraph = None import cherrypy from cherrypy import _cprequest, _cpwsgi from cherrypy.process.plugins import SimplePlugin class ReferrerTree(object): """An object which gathers all referrers of an object to a given depth.""" peek_length = 40 def __init__(self, ignore=None, maxdepth=2, maxparents=10): self.ignore = ignore or [] self.ignore.append(inspect.currentframe().f_back) self.maxdepth = maxdepth self.maxparents = maxparents def ascend(self, obj, depth=1): """Return a nested list containing referrers of the given object.""" depth += 1 parents = [] # Gather all referrers in one step to minimize # cascading references due to repr() logic. refs = gc.get_referrers(obj) self.ignore.append(refs) if len(refs) > self.maxparents: return [('[%s referrers]' % len(refs), [])] try: ascendcode = self.ascend.__code__ except AttributeError: ascendcode = self.ascend.im_func.func_code for parent in refs: if inspect.isframe(parent) and parent.f_code is ascendcode: continue if parent in self.ignore: continue if depth <= self.maxdepth: parents.append((parent, self.ascend(parent, depth))) else: parents.append((parent, [])) return parents def peek(self, s): """Return s, restricted to a sane length.""" if len(s) > (self.peek_length + 3): half = self.peek_length // 2 return s[:half] + '...' + s[-half:] else: return s def _format(self, obj, descend=True): """Return a string representation of a single object.""" if inspect.isframe(obj): filename, lineno, func, context, index = inspect.getframeinfo(obj) return "" % func if not descend: return self.peek(repr(obj)) if isinstance(obj, dict): return '{' + ', '.join(['%s: %s' % (self._format(k, descend=False), self._format(v, descend=False)) for k, v in obj.items()]) + '}' elif isinstance(obj, list): return '[' + ', '.join([self._format(item, descend=False) for item in obj]) + ']' elif isinstance(obj, tuple): return '(' + ', '.join([self._format(item, descend=False) for item in obj]) + ')' r = self.peek(repr(obj)) if isinstance(obj, (str, int, float)): return r return '%s: %s' % (type(obj), r) def format(self, tree): """Return a list of string reprs from a nested list of referrers.""" output = [] def ascend(branch, depth=1): for parent, grandparents in branch: output.append((' ' * depth) + self._format(parent)) if grandparents: ascend(grandparents, depth + 1) ascend(tree) return output def get_instances(cls): return [x for x in gc.get_objects() if isinstance(x, cls)] class RequestCounter(SimplePlugin): def start(self): self.count = 0 def before_request(self): self.count += 1 def after_request(self): self.count -= 1 request_counter = RequestCounter(cherrypy.engine) request_counter.subscribe() def get_context(obj): if isinstance(obj, _cprequest.Request): return 'path=%s;stage=%s' % (obj.path_info, obj.stage) elif isinstance(obj, _cprequest.Response): return 'status=%s' % obj.status elif isinstance(obj, _cpwsgi.AppResponse): return 'PATH_INFO=%s' % obj.environ.get('PATH_INFO', '') elif hasattr(obj, 'tb_lineno'): return 'tb_lineno=%s' % obj.tb_lineno return '' class GCRoot(object): """A CherryPy page handler for testing reference leaks.""" classes = [ (_cprequest.Request, 2, 2, 'Should be 1 in this request thread and 1 in the main thread.'), (_cprequest.Response, 2, 2, 'Should be 1 in this request thread and 1 in the main thread.'), (_cpwsgi.AppResponse, 1, 1, 'Should be 1 in this request thread only.'), ] @cherrypy.expose def index(self): return 'Hello, world!' @cherrypy.expose def stats(self): output = ['Statistics:'] for trial in range(10): if request_counter.count > 0: break time.sleep(0.5) else: output.append('\nNot all requests closed properly.') # gc_collect isn't perfectly synchronous, because it may # break reference cycles that then take time to fully # finalize. Call it thrice and hope for the best. gc.collect() gc.collect() unreachable = gc.collect() if unreachable: if objgraph is not None: final = objgraph.by_type('Nondestructible') if final: objgraph.show_backrefs(final, filename='finalizers.png') trash = {} for x in gc.garbage: trash[type(x)] = trash.get(type(x), 0) + 1 if trash: output.insert(0, '\n%s unreachable objects:' % unreachable) trash = [(v, k) for k, v in trash.items()] trash.sort() for pair in trash: output.append(' ' + repr(pair)) # Check declared classes to verify uncollected instances. # These don't have to be part of a cycle; they can be # any objects that have unanticipated referrers that keep # them from being collected. allobjs = {} for cls, minobj, maxobj, msg in self.classes: allobjs[cls] = get_instances(cls) for cls, minobj, maxobj, msg in self.classes: objs = allobjs[cls] lenobj = len(objs) if lenobj < minobj or lenobj > maxobj: if minobj == maxobj: output.append( '\nExpected %s %r references, got %s.' % (minobj, cls, lenobj)) else: output.append( '\nExpected %s to %s %r references, got %s.' % (minobj, maxobj, cls, lenobj)) for obj in objs: if objgraph is not None: ig = [id(objs), id(inspect.currentframe())] fname = 'graph_%s_%s.png' % (cls.__name__, id(obj)) objgraph.show_backrefs( obj, extra_ignore=ig, max_depth=4, too_many=20, filename=fname, extra_info=get_context) output.append('\nReferrers for %s (refcount=%s):' % (repr(obj), sys.getrefcount(obj))) t = ReferrerTree(ignore=[objs], maxdepth=3) tree = t.ascend(obj) output.extend(t.format(tree)) return '\n'.join(output) SABnzbd-2.3.2/cherrypy/lib/httpauth.py0000644000000000000000000003135313217005257015764 0ustar 00000000000000""" This module defines functions to implement HTTP Digest Authentication (:rfc:`2617`). This has full compliance with 'Digest' and 'Basic' authentication methods. In 'Digest' it supports both MD5 and MD5-sess algorithms. Usage: First use 'doAuth' to request the client authentication for a certain resource. You should send an httplib.UNAUTHORIZED response to the client so he knows he has to authenticate itself. Then use 'parseAuthorization' to retrieve the 'auth_map' used in 'checkResponse'. To use 'checkResponse' you must have already verified the password associated with the 'username' key in 'auth_map' dict. Then you use the 'checkResponse' function to verify if the password matches the one sent by the client. SUPPORTED_ALGORITHM - list of supported 'Digest' algorithms SUPPORTED_QOP - list of supported 'Digest' 'qop'. """ import time from hashlib import md5 from cherrypy._cpcompat import ( base64_decode, ntob, parse_http_list, parse_keqv_list ) __version__ = 1, 0, 1 __author__ = 'Tiago Cogumbreiro ' __credits__ = """ Peter van Kampen for its recipe which implement most of Digest authentication: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/302378 """ __license__ = """ Copyright (c) 2005, Tiago Cogumbreiro All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Sylvain Hellegouarch nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ __all__ = ('digestAuth', 'basicAuth', 'doAuth', 'checkResponse', 'parseAuthorization', 'SUPPORTED_ALGORITHM', 'md5SessionKey', 'calculateNonce', 'SUPPORTED_QOP') ########################################################################## MD5 = 'MD5' MD5_SESS = 'MD5-sess' AUTH = 'auth' AUTH_INT = 'auth-int' SUPPORTED_ALGORITHM = (MD5, MD5_SESS) SUPPORTED_QOP = (AUTH, AUTH_INT) ########################################################################## # doAuth # DIGEST_AUTH_ENCODERS = { MD5: lambda val: md5(ntob(val)).hexdigest(), MD5_SESS: lambda val: md5(ntob(val)).hexdigest(), # SHA: lambda val: sha.new(ntob(val)).hexdigest (), } def calculateNonce(realm, algorithm=MD5): """This is an auxaliary function that calculates 'nonce' value. It is used to handle sessions.""" global SUPPORTED_ALGORITHM, DIGEST_AUTH_ENCODERS assert algorithm in SUPPORTED_ALGORITHM try: encoder = DIGEST_AUTH_ENCODERS[algorithm] except KeyError: raise NotImplementedError('The chosen algorithm (%s) does not have ' 'an implementation yet' % algorithm) return encoder('%d:%s' % (time.time(), realm)) def digestAuth(realm, algorithm=MD5, nonce=None, qop=AUTH): """Challenges the client for a Digest authentication.""" global SUPPORTED_ALGORITHM, DIGEST_AUTH_ENCODERS, SUPPORTED_QOP assert algorithm in SUPPORTED_ALGORITHM assert qop in SUPPORTED_QOP if nonce is None: nonce = calculateNonce(realm, algorithm) return 'Digest realm="%s", nonce="%s", algorithm="%s", qop="%s"' % ( realm, nonce, algorithm, qop ) def basicAuth(realm): """Challengenes the client for a Basic authentication.""" assert '"' not in realm, "Realms cannot contain the \" (quote) character." return 'Basic realm="%s"' % realm def doAuth(realm): """'doAuth' function returns the challenge string b giving priority over Digest and fallback to Basic authentication when the browser doesn't support the first one. This should be set in the HTTP header under the key 'WWW-Authenticate'.""" return digestAuth(realm) + ' ' + basicAuth(realm) ########################################################################## # Parse authorization parameters # def _parseDigestAuthorization(auth_params): # Convert the auth params to a dict items = parse_http_list(auth_params) params = parse_keqv_list(items) # Now validate the params # Check for required parameters required = ['username', 'realm', 'nonce', 'uri', 'response'] for k in required: if k not in params: return None # If qop is sent then cnonce and nc MUST be present if 'qop' in params and not ('cnonce' in params and 'nc' in params): return None # If qop is not sent, neither cnonce nor nc can be present if ('cnonce' in params or 'nc' in params) and \ 'qop' not in params: return None return params def _parseBasicAuthorization(auth_params): username, password = base64_decode(auth_params).split(':', 1) return {'username': username, 'password': password} AUTH_SCHEMES = { 'basic': _parseBasicAuthorization, 'digest': _parseDigestAuthorization, } def parseAuthorization(credentials): """parseAuthorization will convert the value of the 'Authorization' key in the HTTP header to a map itself. If the parsing fails 'None' is returned. """ global AUTH_SCHEMES auth_scheme, auth_params = credentials.split(' ', 1) auth_scheme = auth_scheme.lower() parser = AUTH_SCHEMES[auth_scheme] params = parser(auth_params) if params is None: return assert 'auth_scheme' not in params params['auth_scheme'] = auth_scheme return params ########################################################################## # Check provided response for a valid password # def md5SessionKey(params, password): """ If the "algorithm" directive's value is "MD5-sess", then A1 [the session key] is calculated only once - on the first request by the client following receipt of a WWW-Authenticate challenge from the server. This creates a 'session key' for the authentication of subsequent requests and responses which is different for each "authentication session", thus limiting the amount of material hashed with any one key. Because the server need only use the hash of the user credentials in order to create the A1 value, this construction could be used in conjunction with a third party authentication service so that the web server would not need the actual password value. The specification of such a protocol is beyond the scope of this specification. """ keys = ('username', 'realm', 'nonce', 'cnonce') params_copy = {} for key in keys: params_copy[key] = params[key] params_copy['algorithm'] = MD5_SESS return _A1(params_copy, password) def _A1(params, password): algorithm = params.get('algorithm', MD5) H = DIGEST_AUTH_ENCODERS[algorithm] if algorithm == MD5: # If the "algorithm" directive's value is "MD5" or is # unspecified, then A1 is: # A1 = unq(username-value) ":" unq(realm-value) ":" passwd return '%s:%s:%s' % (params['username'], params['realm'], password) elif algorithm == MD5_SESS: # This is A1 if qop is set # A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) # ":" unq(nonce-value) ":" unq(cnonce-value) h_a1 = H('%s:%s:%s' % (params['username'], params['realm'], password)) return '%s:%s:%s' % (h_a1, params['nonce'], params['cnonce']) def _A2(params, method, kwargs): # If the "qop" directive's value is "auth" or is unspecified, then A2 is: # A2 = Method ":" digest-uri-value qop = params.get('qop', 'auth') if qop == 'auth': return method + ':' + params['uri'] elif qop == 'auth-int': # If the "qop" value is "auth-int", then A2 is: # A2 = Method ":" digest-uri-value ":" H(entity-body) entity_body = kwargs.get('entity_body', '') H = kwargs['H'] return '%s:%s:%s' % ( method, params['uri'], H(entity_body) ) else: raise NotImplementedError("The 'qop' method is unknown: %s" % qop) def _computeDigestResponse(auth_map, password, method='GET', A1=None, **kwargs): """ Generates a response respecting the algorithm defined in RFC 2617 """ params = auth_map algorithm = params.get('algorithm', MD5) H = DIGEST_AUTH_ENCODERS[algorithm] KD = lambda secret, data: H(secret + ':' + data) qop = params.get('qop', None) H_A2 = H(_A2(params, method, kwargs)) if algorithm == MD5_SESS and A1 is not None: H_A1 = H(A1) else: H_A1 = H(_A1(params, password)) if qop in ('auth', 'auth-int'): # If the "qop" value is "auth" or "auth-int": # request-digest = <"> < KD ( H(A1), unq(nonce-value) # ":" nc-value # ":" unq(cnonce-value) # ":" unq(qop-value) # ":" H(A2) # ) <"> request = '%s:%s:%s:%s:%s' % ( params['nonce'], params['nc'], params['cnonce'], params['qop'], H_A2, ) elif qop is None: # If the "qop" directive is not present (this construction is # for compatibility with RFC 2069): # request-digest = # <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> request = '%s:%s' % (params['nonce'], H_A2) return KD(H_A1, request) def _checkDigestResponse(auth_map, password, method='GET', A1=None, **kwargs): """This function is used to verify the response given by the client when he tries to authenticate. Optional arguments: entity_body - when 'qop' is set to 'auth-int' you MUST provide the raw data you are going to send to the client (usually the HTML page. request_uri - the uri from the request line compared with the 'uri' directive of the authorization map. They must represent the same resource (unused at this time). """ if auth_map['realm'] != kwargs.get('realm', None): return False response = _computeDigestResponse( auth_map, password, method, A1, **kwargs) return response == auth_map['response'] def _checkBasicResponse(auth_map, password, method='GET', encrypt=None, **kwargs): # Note that the Basic response doesn't provide the realm value so we cannot # test it pass_through = lambda password, username=None: password encrypt = encrypt or pass_through try: candidate = encrypt(auth_map['password'], auth_map['username']) except TypeError: # if encrypt only takes one parameter, it's the password candidate = encrypt(auth_map['password']) return candidate == password AUTH_RESPONSES = { 'basic': _checkBasicResponse, 'digest': _checkDigestResponse, } def checkResponse(auth_map, password, method='GET', encrypt=None, **kwargs): """'checkResponse' compares the auth_map with the password and optionally other arguments that each implementation might need. If the response is of type 'Basic' then the function has the following signature:: checkBasicResponse(auth_map, password) -> bool If the response is of type 'Digest' then the function has the following signature:: checkDigestResponse(auth_map, password, method='GET', A1=None) -> bool The 'A1' argument is only used in MD5_SESS algorithm based responses. Check md5SessionKey() for more info. """ checker = AUTH_RESPONSES[auth_map['auth_scheme']] return checker(auth_map, password, method=method, encrypt=encrypt, **kwargs) SABnzbd-2.3.2/cherrypy/lib/httputil.py0000644000000000000000000004225713217005257016005 0ustar 00000000000000"""HTTP library functions. This module contains functions for building an HTTP application framework: any one, not just one whose name starts with "Ch". ;) If you reference any modules from some popular framework inside *this* module, FuManChu will personally hang you up by your thumbs and submit you to a public caning. """ import functools import email.utils import re from binascii import b2a_base64 from cgi import parse_header try: # Python 3 from email.header import decode_header except ImportError: from email.Header import decode_header import six from cherrypy._cpcompat import BaseHTTPRequestHandler, ntob, ntou from cherrypy._cpcompat import text_or_bytes, iteritems from cherrypy._cpcompat import reversed, sorted, unquote_qs response_codes = BaseHTTPRequestHandler.responses.copy() # From https://github.com/cherrypy/cherrypy/issues/361 response_codes[500] = ('Internal Server Error', 'The server encountered an unexpected condition ' 'which prevented it from fulfilling the request.') response_codes[503] = ('Service Unavailable', 'The server is currently unable to handle the ' 'request due to a temporary overloading or ' 'maintenance of the server.') HTTPDate = functools.partial(email.utils.formatdate, usegmt=True) def urljoin(*atoms): """Return the given path \*atoms, joined into a single URL. This will correctly join a SCRIPT_NAME and PATH_INFO into the original URL, even if either atom is blank. """ url = '/'.join([x for x in atoms if x]) while '//' in url: url = url.replace('//', '/') # Special-case the final url of "", and return "/" instead. return url or '/' def urljoin_bytes(*atoms): """Return the given path *atoms, joined into a single URL. This will correctly join a SCRIPT_NAME and PATH_INFO into the original URL, even if either atom is blank. """ url = ntob('/').join([x for x in atoms if x]) while ntob('//') in url: url = url.replace(ntob('//'), ntob('/')) # Special-case the final url of "", and return "/" instead. return url or ntob('/') def protocol_from_http(protocol_str): """Return a protocol tuple from the given 'HTTP/x.y' string.""" return int(protocol_str[5]), int(protocol_str[7]) def get_ranges(headervalue, content_length): """Return a list of (start, stop) indices from a Range header, or None. Each (start, stop) tuple will be composed of two ints, which are suitable for use in a slicing operation. That is, the header "Range: bytes=3-6", if applied against a Python string, is requesting resource[3:7]. This function will return the list [(3, 7)]. If this function returns an empty list, you should return HTTP 416. """ if not headervalue: return None result = [] bytesunit, byteranges = headervalue.split('=', 1) for brange in byteranges.split(','): start, stop = [x.strip() for x in brange.split('-', 1)] if start: if not stop: stop = content_length - 1 start, stop = int(start), int(stop) if start >= content_length: # From rfc 2616 sec 14.16: # "If the server receives a request (other than one # including an If-Range request-header field) with an # unsatisfiable Range request-header field (that is, # all of whose byte-range-spec values have a first-byte-pos # value greater than the current length of the selected # resource), it SHOULD return a response code of 416 # (Requested range not satisfiable)." continue if stop < start: # From rfc 2616 sec 14.16: # "If the server ignores a byte-range-spec because it # is syntactically invalid, the server SHOULD treat # the request as if the invalid Range header field # did not exist. (Normally, this means return a 200 # response containing the full entity)." return None result.append((start, stop + 1)) else: if not stop: # See rfc quote above. return None # Negative subscript (last N bytes) # # RFC 2616 Section 14.35.1: # If the entity is shorter than the specified suffix-length, # the entire entity-body is used. if int(stop) > content_length: result.append((0, content_length)) else: result.append((content_length - int(stop), content_length)) return result class HeaderElement(object): """An element (with parameters) from an HTTP header's element list.""" def __init__(self, value, params=None): self.value = value if params is None: params = {} self.params = params def __cmp__(self, other): return cmp(self.value, other.value) def __lt__(self, other): return self.value < other.value def __str__(self): p = [';%s=%s' % (k, v) for k, v in iteritems(self.params)] return str('%s%s' % (self.value, ''.join(p))) def __bytes__(self): return ntob(self.__str__()) def __unicode__(self): return ntou(self.__str__()) @staticmethod def parse(elementstr): """Transform 'token;key=val' to ('token', {'key': 'val'}).""" initial_value, params = parse_header(elementstr) return initial_value, params @classmethod def from_str(cls, elementstr): """Construct an instance from a string of the form 'token;key=val'.""" ival, params = cls.parse(elementstr) return cls(ival, params) q_separator = re.compile(r'; *q *=') class AcceptElement(HeaderElement): """An element (with parameters) from an Accept* header's element list. AcceptElement objects are comparable; the more-preferred object will be "less than" the less-preferred object. They are also therefore sortable; if you sort a list of AcceptElement objects, they will be listed in priority order; the most preferred value will be first. Yes, it should have been the other way around, but it's too late to fix now. """ @classmethod def from_str(cls, elementstr): qvalue = None # The first "q" parameter (if any) separates the initial # media-range parameter(s) (if any) from the accept-params. atoms = q_separator.split(elementstr, 1) media_range = atoms.pop(0).strip() if atoms: # The qvalue for an Accept header can have extensions. The other # headers cannot, but it's easier to parse them as if they did. qvalue = HeaderElement.from_str(atoms[0].strip()) media_type, params = cls.parse(media_range) if qvalue is not None: params['q'] = qvalue return cls(media_type, params) @property def qvalue(self): 'The qvalue, or priority, of this value.' val = self.params.get('q', '1') if isinstance(val, HeaderElement): val = val.value return float(val) def __cmp__(self, other): diff = cmp(self.qvalue, other.qvalue) if diff == 0: diff = cmp(str(self), str(other)) return diff def __lt__(self, other): if self.qvalue == other.qvalue: return str(self) < str(other) else: return self.qvalue < other.qvalue RE_HEADER_SPLIT = re.compile(',(?=(?:[^"]*"[^"]*")*[^"]*$)') def header_elements(fieldname, fieldvalue): """Return a sorted HeaderElement list from a comma-separated header string. """ if not fieldvalue: return [] result = [] for element in RE_HEADER_SPLIT.split(fieldvalue): if fieldname.startswith('Accept') or fieldname == 'TE': hv = AcceptElement.from_str(element) else: hv = HeaderElement.from_str(element) result.append(hv) return list(reversed(sorted(result))) def decode_TEXT(value): r"""Decode :rfc:`2047` TEXT (e.g. "=?utf-8?q?f=C3=BCr?=" -> "f\xfcr").""" atoms = decode_header(value) decodedvalue = '' for atom, charset in atoms: if charset is not None: atom = atom.decode(charset) decodedvalue += atom return decodedvalue def valid_status(status): """Return legal HTTP status Code, Reason-phrase and Message. The status arg must be an int, or a str that begins with an int. If status is an int, or a str and no reason-phrase is supplied, a default reason-phrase will be provided. """ if not status: status = 200 status = str(status) parts = status.split(' ', 1) if len(parts) == 1: # No reason supplied. code, = parts reason = None else: code, reason = parts reason = reason.strip() try: code = int(code) except ValueError: raise ValueError('Illegal response status from server ' '(%s is non-numeric).' % repr(code)) if code < 100 or code > 599: raise ValueError('Illegal response status from server ' '(%s is out of range).' % repr(code)) if code not in response_codes: # code is unknown but not illegal default_reason, message = '', '' else: default_reason, message = response_codes[code] if reason is None: reason = default_reason return code, reason, message # NOTE: the parse_qs functions that follow are modified version of those # in the python3.0 source - we need to pass through an encoding to the unquote # method, but the default parse_qs function doesn't allow us to. These do. def _parse_qs(qs, keep_blank_values=0, strict_parsing=0, encoding='utf-8'): """Parse a query given as a string argument. Arguments: qs: URL-encoded query string to be parsed keep_blank_values: flag indicating whether blank values in URL encoded queries should be treated as blank strings. A true value indicates that blanks should be retained as blank strings. The default false value indicates that blank values are to be ignored and treated as if they were not included. strict_parsing: flag indicating what to do with parsing errors. If false (the default), errors are silently ignored. If true, errors raise a ValueError exception. Returns a dict, as G-d intended. """ pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')] d = {} for name_value in pairs: if not name_value and not strict_parsing: continue nv = name_value.split('=', 1) if len(nv) != 2: if strict_parsing: raise ValueError('bad query field: %r' % (name_value,)) # Handle case of a control-name with no equal sign if keep_blank_values: nv.append('') else: continue if len(nv[1]) or keep_blank_values: name = unquote_qs(nv[0], encoding) value = unquote_qs(nv[1], encoding) if name in d: if not isinstance(d[name], list): d[name] = [d[name]] d[name].append(value) else: d[name] = value return d image_map_pattern = re.compile(r'[0-9]+,[0-9]+') def parse_query_string(query_string, keep_blank_values=True, encoding='utf-8'): """Build a params dictionary from a query_string. Duplicate key/value pairs in the provided query_string will be returned as {'key': [val1, val2, ...]}. Single key/values will be returned as strings: {'key': 'value'}. """ if image_map_pattern.match(query_string): # Server-side image map. Map the coords to 'x' and 'y' # (like CGI::Request does). pm = query_string.split(',') pm = {'x': int(pm[0]), 'y': int(pm[1])} else: pm = _parse_qs(query_string, keep_blank_values, encoding=encoding) return pm class CaseInsensitiveDict(dict): """A case-insensitive dict subclass. Each key is changed on entry to str(key).title(). """ def __getitem__(self, key): return dict.__getitem__(self, str(key).title()) def __setitem__(self, key, value): dict.__setitem__(self, str(key).title(), value) def __delitem__(self, key): dict.__delitem__(self, str(key).title()) def __contains__(self, key): return dict.__contains__(self, str(key).title()) def get(self, key, default=None): return dict.get(self, str(key).title(), default) if hasattr({}, 'has_key'): def has_key(self, key): return str(key).title() in self def update(self, E): for k in E.keys(): self[str(k).title()] = E[k] @classmethod def fromkeys(cls, seq, value=None): newdict = cls() for k in seq: newdict[str(k).title()] = value return newdict def setdefault(self, key, x=None): key = str(key).title() try: return self[key] except KeyError: self[key] = x return x def pop(self, key, default): return dict.pop(self, str(key).title(), default) # TEXT = # # A CRLF is allowed in the definition of TEXT only as part of a header # field continuation. It is expected that the folding LWS will be # replaced with a single SP before interpretation of the TEXT value." if str == bytes: header_translate_table = ''.join([chr(i) for i in xrange(256)]) header_translate_deletechars = ''.join( [chr(i) for i in xrange(32)]) + chr(127) else: header_translate_table = None header_translate_deletechars = bytes(range(32)) + bytes([127]) class HeaderMap(CaseInsensitiveDict): """A dict subclass for HTTP request and response headers. Each key is changed on entry to str(key).title(). This allows headers to be case-insensitive and avoid duplicates. Values are header values (decoded according to :rfc:`2047` if necessary). """ protocol = (1, 1) encodings = ['ISO-8859-1'] # Someday, when http-bis is done, this will probably get dropped # since few servers, clients, or intermediaries do it. But until then, # we're going to obey the spec as is. # "Words of *TEXT MAY contain characters from character sets other than # ISO-8859-1 only when encoded according to the rules of RFC 2047." use_rfc_2047 = True def elements(self, key): """Return a sorted list of HeaderElements for the given header.""" key = str(key).title() value = self.get(key) return header_elements(key, value) def values(self, key): """Return a sorted list of HeaderElement.value for the given header.""" return [e.value for e in self.elements(key)] def output(self): """Transform self into a list of (name, value) tuples.""" return list(self.encode_header_items(self.items())) @classmethod def encode_header_items(cls, header_items): """ Prepare the sequence of name, value tuples into a form suitable for transmitting on the wire for HTTP. """ for k, v in header_items: if isinstance(k, six.text_type): k = cls.encode(k) if not isinstance(v, text_or_bytes): v = str(v) if isinstance(v, six.text_type): v = cls.encode(v) # See header_translate_* constants above. # Replace only if you really know what you're doing. k = k.translate(header_translate_table, header_translate_deletechars) v = v.translate(header_translate_table, header_translate_deletechars) yield (k, v) @classmethod def encode(cls, v): """Return the given header name or value, encoded for HTTP output.""" for enc in cls.encodings: try: return v.encode(enc) except UnicodeEncodeError: continue if cls.protocol == (1, 1) and cls.use_rfc_2047: # Encode RFC-2047 TEXT # (e.g. u"\u8200" -> "=?utf-8?b?6IiA?="). # We do our own here instead of using the email module # because we never want to fold lines--folding has # been deprecated by the HTTP working group. v = b2a_base64(v.encode('utf-8')) return (ntob('=?utf-8?b?') + v.strip(ntob('\n')) + ntob('?=')) raise ValueError('Could not encode header part %r using ' 'any of the encodings %r.' % (v, cls.encodings)) class Host(object): """An internet address. name Should be the client's host name. If not available (because no DNS lookup is performed), the IP address should be used instead. """ ip = '0.0.0.0' port = 80 name = 'unknown.tld' def __init__(self, ip, port, name=None): self.ip = ip self.port = port if name is None: name = ip self.name = name def __repr__(self): return 'httputil.Host(%r, %r, %r)' % (self.ip, self.port, self.name) SABnzbd-2.3.2/cherrypy/lib/jsontools.py0000644000000000000000000000752413217005257016160 0ustar 00000000000000import cherrypy from cherrypy._cpcompat import text_or_bytes, ntou, json_encode, json_decode def json_processor(entity): """Read application/json data into request.json.""" if not entity.headers.get(ntou('Content-Length'), ntou('')): raise cherrypy.HTTPError(411) body = entity.fp.read() with cherrypy.HTTPError.handle(ValueError, 400, 'Invalid JSON document'): cherrypy.serving.request.json = json_decode(body.decode('utf-8')) def json_in(content_type=[ntou('application/json'), ntou('text/javascript')], force=True, debug=False, processor=json_processor): """Add a processor to parse JSON request entities: The default processor places the parsed data into request.json. Incoming request entities which match the given content_type(s) will be deserialized from JSON to the Python equivalent, and the result stored at cherrypy.request.json. The 'content_type' argument may be a Content-Type string or a list of allowable Content-Type strings. If the 'force' argument is True (the default), then entities of other content types will not be allowed; "415 Unsupported Media Type" is raised instead. Supply your own processor to use a custom decoder, or to handle the parsed data differently. The processor can be configured via tools.json_in.processor or via the decorator method. Note that the deserializer requires the client send a Content-Length request header, or it will raise "411 Length Required". If for any other reason the request entity cannot be deserialized from JSON, it will raise "400 Bad Request: Invalid JSON document". You must be using Python 2.6 or greater, or have the 'simplejson' package importable; otherwise, ValueError is raised during processing. """ request = cherrypy.serving.request if isinstance(content_type, text_or_bytes): content_type = [content_type] if force: if debug: cherrypy.log('Removing body processors %s' % repr(request.body.processors.keys()), 'TOOLS.JSON_IN') request.body.processors.clear() request.body.default_proc = cherrypy.HTTPError( 415, 'Expected an entity of content type %s' % ', '.join(content_type)) for ct in content_type: if debug: cherrypy.log('Adding body processor for %s' % ct, 'TOOLS.JSON_IN') request.body.processors[ct] = processor def json_handler(*args, **kwargs): value = cherrypy.serving.request._json_inner_handler(*args, **kwargs) return json_encode(value) def json_out(content_type='application/json', debug=False, handler=json_handler): """Wrap request.handler to serialize its output to JSON. Sets Content-Type. If the given content_type is None, the Content-Type response header is not set. Provide your own handler to use a custom encoder. For example cherrypy.config['tools.json_out.handler'] = , or @json_out(handler=function). You must be using Python 2.6 or greater, or have the 'simplejson' package importable; otherwise, ValueError is raised during processing. """ request = cherrypy.serving.request # request.handler may be set to None by e.g. the caching tool # to signal to all components that a response body has already # been attached, in which case we don't need to wrap anything. if request.handler is None: return if debug: cherrypy.log('Replacing %s with JSON handler' % request.handler, 'TOOLS.JSON_OUT') request._json_inner_handler = request.handler request.handler = handler if content_type is not None: if debug: cherrypy.log('Setting Content-Type to %s' % content_type, 'TOOLS.JSON_OUT') cherrypy.serving.response.headers['Content-Type'] = content_type SABnzbd-2.3.2/cherrypy/lib/lockfile.py0000644000000000000000000000611613217005257015712 0ustar 00000000000000""" Platform-independent file locking. Inspired by and modeled after zc.lockfile. """ import os try: import msvcrt except ImportError: pass try: import fcntl except ImportError: pass class LockError(Exception): 'Could not obtain a lock' msg = 'Unable to lock %r' def __init__(self, path): super(LockError, self).__init__(self.msg % path) class UnlockError(LockError): 'Could not release a lock' msg = 'Unable to unlock %r' # first, a default, naive locking implementation class LockFile(object): """ A default, naive locking implementation. Always fails if the file already exists. """ def __init__(self, path): self.path = path try: fd = os.open(path, os.O_CREAT | os.O_WRONLY | os.O_EXCL) except OSError: raise LockError(self.path) os.close(fd) def release(self): os.remove(self.path) def remove(self): pass class SystemLockFile(object): """ An abstract base class for platform-specific locking. """ def __init__(self, path): self.path = path try: # Open lockfile for writing without truncation: self.fp = open(path, 'r+') except IOError: # If the file doesn't exist, IOError is raised; Use a+ instead. # Note that there may be a race here. Multiple processes # could fail on the r+ open and open the file a+, but only # one will get the the lock and write a pid. self.fp = open(path, 'a+') try: self._lock_file() except: self.fp.seek(1) self.fp.close() del self.fp raise self.fp.write(' %s\n' % os.getpid()) self.fp.truncate() self.fp.flush() def release(self): if not hasattr(self, 'fp'): return self._unlock_file() self.fp.close() del self.fp def remove(self): """ Attempt to remove the file """ try: os.remove(self.path) except: pass def _unlock_file(self): """Attempt to obtain the lock on self.fp. Raise UnlockError if not released.""" class WindowsLockFile(SystemLockFile): def _lock_file(self): # Lock just the first byte try: msvcrt.locking(self.fp.fileno(), msvcrt.LK_NBLCK, 1) except IOError: raise LockError(self.fp.name) def _unlock_file(self): try: self.fp.seek(0) msvcrt.locking(self.fp.fileno(), msvcrt.LK_UNLCK, 1) except IOError: raise UnlockError(self.fp.name) if 'msvcrt' in globals(): LockFile = WindowsLockFile class UnixLockFile(SystemLockFile): def _lock_file(self): flags = fcntl.LOCK_EX | fcntl.LOCK_NB try: fcntl.flock(self.fp.fileno(), flags) except IOError: raise LockError(self.fp.name) # no need to implement _unlock_file, it will be unlocked on close() if 'fcntl' in globals(): LockFile = UnixLockFile SABnzbd-2.3.2/cherrypy/lib/locking.py0000644000000000000000000000231013217005257015540 0ustar 00000000000000import datetime class NeverExpires(object): def expired(self): return False class Timer(object): """ A simple timer that will indicate when an expiration time has passed. """ def __init__(self, expiration): 'Create a timer that expires at `expiration` (UTC datetime)' self.expiration = expiration @classmethod def after(cls, elapsed): """ Return a timer that will expire after `elapsed` passes. """ return cls(datetime.datetime.utcnow() + elapsed) def expired(self): return datetime.datetime.utcnow() >= self.expiration class LockTimeout(Exception): 'An exception when a lock could not be acquired before a timeout period' class LockChecker(object): """ Keep track of the time and detect if a timeout has expired """ def __init__(self, session_id, timeout): self.session_id = session_id if timeout: self.timer = Timer.after(timeout) else: self.timer = NeverExpires() def expired(self): if self.timer.expired(): raise LockTimeout( 'Timeout acquiring lock for %(session_id)s' % vars(self)) return False SABnzbd-2.3.2/cherrypy/lib/profiler.py0000644000000000000000000001451213217005257015743 0ustar 00000000000000"""Profiler tools for CherryPy. CherryPy users ============== You can profile any of your pages as follows:: from cherrypy.lib import profiler class Root: p = profiler.Profiler("/path/to/profile/dir") @cherrypy.expose def index(self): self.p.run(self._index) def _index(self): return "Hello, world!" cherrypy.tree.mount(Root()) You can also turn on profiling for all requests using the ``make_app`` function as WSGI middleware. CherryPy developers =================== This module can be used whenever you make changes to CherryPy, to get a quick sanity-check on overall CP performance. Use the ``--profile`` flag when running the test suite. Then, use the ``serve()`` function to browse the results in a web browser. If you run this module from the command line, it will call ``serve()`` for you. """ import io import os import os.path import sys import warnings import cherrypy try: import profile import pstats def new_func_strip_path(func_name): """Make profiler output more readable by adding `__init__` modules' parents """ filename, line, name = func_name if filename.endswith('__init__.py'): return os.path.basename(filename[:-12]) + filename[-12:], line, name return os.path.basename(filename), line, name pstats.func_strip_path = new_func_strip_path except ImportError: profile = None pstats = None _count = 0 class Profiler(object): def __init__(self, path=None): if not path: path = os.path.join(os.path.dirname(__file__), 'profile') self.path = path if not os.path.exists(path): os.makedirs(path) def run(self, func, *args, **params): """Dump profile data into self.path.""" global _count c = _count = _count + 1 path = os.path.join(self.path, 'cp_%04d.prof' % c) prof = profile.Profile() result = prof.runcall(func, *args, **params) prof.dump_stats(path) return result def statfiles(self): """:rtype: list of available profiles. """ return [f for f in os.listdir(self.path) if f.startswith('cp_') and f.endswith('.prof')] def stats(self, filename, sortby='cumulative'): """:rtype stats(index): output of print_stats() for the given profile. """ sio = io.StringIO() if sys.version_info >= (2, 5): s = pstats.Stats(os.path.join(self.path, filename), stream=sio) s.strip_dirs() s.sort_stats(sortby) s.print_stats() else: # pstats.Stats before Python 2.5 didn't take a 'stream' arg, # but just printed to stdout. So re-route stdout. s = pstats.Stats(os.path.join(self.path, filename)) s.strip_dirs() s.sort_stats(sortby) oldout = sys.stdout try: sys.stdout = sio s.print_stats() finally: sys.stdout = oldout response = sio.getvalue() sio.close() return response @cherrypy.expose def index(self): return """ CherryPy profile data """ @cherrypy.expose def menu(self): yield '

Profiling runs

' yield '

Click on one of the runs below to see profiling data.

' runs = self.statfiles() runs.sort() for i in runs: yield "%s
" % ( i, i) @cherrypy.expose def report(self, filename): cherrypy.response.headers['Content-Type'] = 'text/plain' return self.stats(filename) class ProfileAggregator(Profiler): def __init__(self, path=None): Profiler.__init__(self, path) global _count self.count = _count = _count + 1 self.profiler = profile.Profile() def run(self, func, *args, **params): path = os.path.join(self.path, 'cp_%04d.prof' % self.count) result = self.profiler.runcall(func, *args, **params) self.profiler.dump_stats(path) return result class make_app: def __init__(self, nextapp, path=None, aggregate=False): """Make a WSGI middleware app which wraps 'nextapp' with profiling. nextapp the WSGI application to wrap, usually an instance of cherrypy.Application. path where to dump the profiling output. aggregate if True, profile data for all HTTP requests will go in a single file. If False (the default), each HTTP request will dump its profile data into a separate file. """ if profile is None or pstats is None: msg = ('Your installation of Python does not have a profile ' "module. If you're on Debian, try " '`sudo apt-get install python-profiler`. ' 'See http://www.cherrypy.org/wiki/ProfilingOnDebian ' 'for details.') warnings.warn(msg) self.nextapp = nextapp self.aggregate = aggregate if aggregate: self.profiler = ProfileAggregator(path) else: self.profiler = Profiler(path) def __call__(self, environ, start_response): def gather(): result = [] for line in self.nextapp(environ, start_response): result.append(line) return result return self.profiler.run(gather) def serve(path=None, port=8080): if profile is None or pstats is None: msg = ('Your installation of Python does not have a profile module. ' "If you're on Debian, try " '`sudo apt-get install python-profiler`. ' 'See http://www.cherrypy.org/wiki/ProfilingOnDebian ' 'for details.') warnings.warn(msg) cherrypy.config.update({'server.socket_port': int(port), 'server.thread_pool': 10, 'environment': 'production', }) cherrypy.quickstart(Profiler(path)) if __name__ == '__main__': serve(*tuple(sys.argv[1:])) SABnzbd-2.3.2/cherrypy/lib/reprconf.py0000644000000000000000000003737213217005257015750 0ustar 00000000000000"""Generic configuration system using unrepr. Configuration data may be supplied as a Python dictionary, as a filename, or as an open file object. When you supply a filename or file, Python's builtin ConfigParser is used (with some extensions). Namespaces ---------- Configuration keys are separated into namespaces by the first "." in the key. The only key that cannot exist in a namespace is the "environment" entry. This special entry 'imports' other config entries from a template stored in the Config.environments dict. You can define your own namespaces to be called when new config is merged by adding a named handler to Config.namespaces. The name can be any string, and the handler must be either a callable or a context manager. """ try: # Python 3.0+ from configparser import ConfigParser except ImportError: from ConfigParser import ConfigParser try: text_or_bytes except NameError: text_or_bytes = str try: # Python 3 import builtins except ImportError: # Python 2 import __builtin__ as builtins import operator as _operator import sys def as_dict(config): """Return a dict from 'config' whether it is a dict, file, or filename.""" if isinstance(config, text_or_bytes): config = Parser().dict_from_file(config) elif hasattr(config, 'read'): config = Parser().dict_from_file(config) return config class NamespaceSet(dict): """A dict of config namespace names and handlers. Each config entry should begin with a namespace name; the corresponding namespace handler will be called once for each config entry in that namespace, and will be passed two arguments: the config key (with the namespace removed) and the config value. Namespace handlers may be any Python callable; they may also be Python 2.5-style 'context managers', in which case their __enter__ method should return a callable to be used as the handler. See cherrypy.tools (the Toolbox class) for an example. """ def __call__(self, config): """Iterate through config and pass it to each namespace handler. config A flat dict, where keys use dots to separate namespaces, and values are arbitrary. The first name in each config key is used to look up the corresponding namespace handler. For example, a config entry of {'tools.gzip.on': v} will call the 'tools' namespace handler with the args: ('gzip.on', v) """ # Separate the given config into namespaces ns_confs = {} for k in config: if '.' in k: ns, name = k.split('.', 1) bucket = ns_confs.setdefault(ns, {}) bucket[name] = config[k] # I chose __enter__ and __exit__ so someday this could be # rewritten using Python 2.5's 'with' statement: # for ns, handler in self.iteritems(): # with handler as callable: # for k, v in ns_confs.get(ns, {}).iteritems(): # callable(k, v) for ns, handler in self.items(): exit = getattr(handler, '__exit__', None) if exit: callable = handler.__enter__() no_exc = True try: try: for k, v in ns_confs.get(ns, {}).items(): callable(k, v) except: # The exceptional case is handled here no_exc = False if exit is None: raise if not exit(*sys.exc_info()): raise # The exception is swallowed if exit() returns true finally: # The normal and non-local-goto cases are handled here if no_exc and exit: exit(None, None, None) else: for k, v in ns_confs.get(ns, {}).items(): handler(k, v) def __repr__(self): return '%s.%s(%s)' % (self.__module__, self.__class__.__name__, dict.__repr__(self)) def __copy__(self): newobj = self.__class__() newobj.update(self) return newobj copy = __copy__ class Config(dict): """A dict-like set of configuration data, with defaults and namespaces. May take a file, filename, or dict. """ defaults = {} environments = {} namespaces = NamespaceSet() def __init__(self, file=None, **kwargs): self.reset() if file is not None: self.update(file) if kwargs: self.update(kwargs) def reset(self): """Reset self to default values.""" self.clear() dict.update(self, self.defaults) def update(self, config): """Update self from a dict, file or filename.""" if isinstance(config, text_or_bytes): # Filename config = Parser().dict_from_file(config) elif hasattr(config, 'read'): # Open file object config = Parser().dict_from_file(config) else: config = config.copy() self._apply(config) def _apply(self, config): """Update self from a dict.""" which_env = config.get('environment') if which_env: env = self.environments[which_env] for k in env: if k not in config: config[k] = env[k] dict.update(self, config) self.namespaces(config) def __setitem__(self, k, v): dict.__setitem__(self, k, v) self.namespaces({k: v}) class Parser(ConfigParser): """Sub-class of ConfigParser that keeps the case of options and that raises an exception if the file cannot be read. """ def optionxform(self, optionstr): return optionstr def read(self, filenames): if isinstance(filenames, text_or_bytes): filenames = [filenames] for filename in filenames: # try: # fp = open(filename) # except IOError: # continue fp = open(filename) try: self._read(fp, filename) finally: fp.close() def as_dict(self, raw=False, vars=None): """Convert an INI file to a dictionary""" # Load INI file into a dict result = {} for section in self.sections(): if section not in result: result[section] = {} for option in self.options(section): value = self.get(section, option, raw=raw, vars=vars) try: value = unrepr(value) except Exception: x = sys.exc_info()[1] msg = ('Config error in section: %r, option: %r, ' 'value: %r. Config values must be valid Python.' % (section, option, value)) raise ValueError(msg, x.__class__.__name__, x.args) result[section][option] = value return result def dict_from_file(self, file): if hasattr(file, 'read'): self.readfp(file) else: self.read(file) return self.as_dict() # public domain "unrepr" implementation, found on the web and then improved. class _Builder2: def build(self, o): m = getattr(self, 'build_' + o.__class__.__name__, None) if m is None: raise TypeError('unrepr does not recognize %s' % repr(o.__class__.__name__)) return m(o) def astnode(self, s): """Return a Python2 ast Node compiled from a string.""" try: import compiler except ImportError: # Fallback to eval when compiler package is not available, # e.g. IronPython 1.0. return eval(s) p = compiler.parse('__tempvalue__ = ' + s) return p.getChildren()[1].getChildren()[0].getChildren()[1] def build_Subscript(self, o): expr, flags, subs = o.getChildren() expr = self.build(expr) subs = self.build(subs) return expr[subs] def build_CallFunc(self, o): children = o.getChildren() # Build callee from first child callee = self.build(children[0]) # Build args and kwargs from remaining children args = [] kwargs = {} for child in children[1:]: class_name = child.__class__.__name__ # None is ignored if class_name == 'NoneType': continue # Keywords become kwargs if class_name == 'Keyword': kwargs.update(self.build(child)) # Everything else becomes args else : args.append(self.build(child)) return callee(*args, **kwargs) def build_Keyword(self, o): key, value_obj = o.getChildren() value = self.build(value_obj) kw_dict = {key: value} return kw_dict def build_List(self, o): return map(self.build, o.getChildren()) def build_Const(self, o): return o.value def build_Dict(self, o): d = {} i = iter(map(self.build, o.getChildren())) for el in i: d[el] = i.next() return d def build_Tuple(self, o): return tuple(self.build_List(o)) def build_Name(self, o): name = o.name if name == 'None': return None if name == 'True': return True if name == 'False': return False # See if the Name is a package or module. If it is, import it. try: return modules(name) except ImportError: pass # See if the Name is in builtins. try: return getattr(builtins, name) except AttributeError: pass raise TypeError('unrepr could not resolve the name %s' % repr(name)) def build_Add(self, o): left, right = map(self.build, o.getChildren()) return left + right def build_Mul(self, o): left, right = map(self.build, o.getChildren()) return left * right def build_Getattr(self, o): parent = self.build(o.expr) return getattr(parent, o.attrname) def build_NoneType(self, o): return None def build_UnarySub(self, o): return -self.build(o.getChildren()[0]) def build_UnaryAdd(self, o): return self.build(o.getChildren()[0]) class _Builder3: def build(self, o): m = getattr(self, 'build_' + o.__class__.__name__, None) if m is None: raise TypeError('unrepr does not recognize %s' % repr(o.__class__.__name__)) return m(o) def astnode(self, s): """Return a Python3 ast Node compiled from a string.""" try: import ast except ImportError: # Fallback to eval when ast package is not available, # e.g. IronPython 1.0. return eval(s) p = ast.parse('__tempvalue__ = ' + s) return p.body[0].value def build_Subscript(self, o): return self.build(o.value)[self.build(o.slice)] def build_Index(self, o): return self.build(o.value) def _build_call35(self, o): """ Workaround for python 3.5 _ast.Call signature, docs found here https://greentreesnakes.readthedocs.org/en/latest/nodes.html """ import ast callee = self.build(o.func) args = [] if o.args is not None: for a in o.args: if isinstance(a, ast.Starred): args.append(self.build(a.value)) else: args.append(self.build(a)) kwargs = {} for kw in o.keywords: if kw.arg is None: # double asterix `**` rst = self.build(kw.value) if not isinstance(rst, dict): raise TypeError('Invalid argument for call.' 'Must be a mapping object.') # give preference to the keys set directly from arg=value for k, v in rst.items(): if k not in kwargs: kwargs[k] = v else: # defined on the call as: arg=value kwargs[kw.arg] = self.build(kw.value) return callee(*args, **kwargs) def build_Call(self, o): if sys.version_info >= (3, 5): return self._build_call35(o) callee = self.build(o.func) if o.args is None: args = () else: args = tuple([self.build(a) for a in o.args]) if o.starargs is None: starargs = () else: starargs = tuple(self.build(o.starargs)) if o.kwargs is None: kwargs = {} else: kwargs = self.build(o.kwargs) if o.keywords is not None: # direct a=b keywords for kw in o.keywords: # preference because is a direct keyword against **kwargs kwargs[kw.arg] = self.build(kw.value) return callee(*(args + starargs), **kwargs) def build_List(self, o): return list(map(self.build, o.elts)) def build_Str(self, o): return o.s def build_Num(self, o): return o.n def build_Dict(self, o): return dict([(self.build(k), self.build(v)) for k, v in zip(o.keys, o.values)]) def build_Tuple(self, o): return tuple(self.build_List(o)) def build_Name(self, o): name = o.id if name == 'None': return None if name == 'True': return True if name == 'False': return False # See if the Name is a package or module. If it is, import it. try: return modules(name) except ImportError: pass # See if the Name is in builtins. try: import builtins return getattr(builtins, name) except AttributeError: pass raise TypeError('unrepr could not resolve the name %s' % repr(name)) def build_NameConstant(self, o): return o.value def build_UnaryOp(self, o): op, operand = map(self.build, [o.op, o.operand]) return op(operand) def build_BinOp(self, o): left, op, right = map(self.build, [o.left, o.op, o.right]) return op(left, right) def build_Add(self, o): return _operator.add def build_Mult(self, o): return _operator.mul def build_USub(self, o): return _operator.neg def build_Attribute(self, o): parent = self.build(o.value) return getattr(parent, o.attr) def build_NoneType(self, o): return None def unrepr(s): """Return a Python object compiled from a string.""" if not s: return s if sys.version_info < (3, 0): b = _Builder2() else: b = _Builder3() obj = b.astnode(s) return b.build(obj) def modules(modulePath): """Load a module and retrieve a reference to that module.""" __import__(modulePath) return sys.modules[modulePath] def attributes(full_attribute_name): """Load a module and retrieve an attribute of that module.""" # Parse out the path, module, and attribute last_dot = full_attribute_name.rfind('.') attr_name = full_attribute_name[last_dot + 1:] mod_path = full_attribute_name[:last_dot] mod = modules(mod_path) # Let an AttributeError propagate outward. try: attr = getattr(mod, attr_name) except AttributeError: raise AttributeError("'%s' object has no attribute '%s'" % (mod_path, attr_name)) # Return a reference to the attribute. return attr SABnzbd-2.3.2/cherrypy/lib/sessions.py0000644000000000000000000007334613217005257016001 0ustar 00000000000000"""Session implementation for CherryPy. You need to edit your config file to use sessions. Here's an example:: [/] tools.sessions.on = True tools.sessions.storage_class = cherrypy.lib.sessions.FileSession tools.sessions.storage_path = "/home/site/sessions" tools.sessions.timeout = 60 This sets the session to be stored in files in the directory /home/site/sessions, and the session timeout to 60 minutes. If you omit ``storage_class``, the sessions will be saved in RAM. ``tools.sessions.on`` is the only required line for working sessions, the rest are optional. By default, the session ID is passed in a cookie, so the client's browser must have cookies enabled for your site. To set data for the current session, use ``cherrypy.session['fieldname'] = 'fieldvalue'``; to get data use ``cherrypy.session.get('fieldname')``. ================ Locking sessions ================ By default, the ``'locking'`` mode of sessions is ``'implicit'``, which means the session is locked early and unlocked late. Be mindful of this default mode for any requests that take a long time to process (streaming responses, expensive calculations, database lookups, API calls, etc), as other concurrent requests that also utilize sessions will hang until the session is unlocked. If you want to control when the session data is locked and unlocked, set ``tools.sessions.locking = 'explicit'``. Then call ``cherrypy.session.acquire_lock()`` and ``cherrypy.session.release_lock()``. Regardless of which mode you use, the session is guaranteed to be unlocked when the request is complete. ================= Expiring Sessions ================= You can force a session to expire with :func:`cherrypy.lib.sessions.expire`. Simply call that function at the point you want the session to expire, and it will cause the session cookie to expire client-side. =========================== Session Fixation Protection =========================== If CherryPy receives, via a request cookie, a session id that it does not recognize, it will reject that id and create a new one to return in the response cookie. This `helps prevent session fixation attacks `_. However, CherryPy "recognizes" a session id by looking up the saved session data for that id. Therefore, if you never save any session data, **you will get a new session id for every request**. ================ Sharing Sessions ================ If you run multiple instances of CherryPy (for example via mod_python behind Apache prefork), you most likely cannot use the RAM session backend, since each instance of CherryPy will have its own memory space. Use a different backend instead, and verify that all instances are pointing at the same file or db location. Alternately, you might try a load balancer which makes sessions "sticky". Google is your friend, there. ================ Expiration Dates ================ The response cookie will possess an expiration date to inform the client at which point to stop sending the cookie back in requests. If the server time and client time differ, expect sessions to be unreliable. **Make sure the system time of your server is accurate**. CherryPy defaults to a 60-minute session timeout, which also applies to the cookie which is sent to the client. Unfortunately, some versions of Safari ("4 public beta" on Windows XP at least) appear to have a bug in their parsing of the GMT expiration date--they appear to interpret the date as one hour in the past. Sixty minutes minus one hour is pretty close to zero, so you may experience this bug as a new session id for every request, unless the requests are less than one second apart. To fix, try increasing the session.timeout. On the other extreme, some users report Firefox sending cookies after their expiration date, although this was on a system with an inaccurate system time. Maybe FF doesn't trust system time. """ import sys import datetime import os import time import threading import cherrypy from cherrypy._cpcompat import copyitems, pickle, random20 from cherrypy.lib import httputil from cherrypy.lib import lockfile from cherrypy.lib import locking from cherrypy.lib import is_iterator missing = object() class Session(object): """A CherryPy dict-like Session object (one per request).""" _id = None id_observers = None "A list of callbacks to which to pass new id's." def _get_id(self): return self._id def _set_id(self, value): self._id = value for o in self.id_observers: o(value) id = property(_get_id, _set_id, doc='The current session ID.') timeout = 60 'Number of minutes after which to delete session data.' locked = False """ If True, this session instance has exclusive read/write access to session data.""" loaded = False """ If True, data has been retrieved from storage. This should happen automatically on the first attempt to access session data.""" clean_thread = None 'Class-level Monitor which calls self.clean_up.' clean_freq = 5 'The poll rate for expired session cleanup in minutes.' originalid = None 'The session id passed by the client. May be missing or unsafe.' missing = False 'True if the session requested by the client did not exist.' regenerated = False """ True if the application called session.regenerate(). This is not set by internal calls to regenerate the session id.""" debug = False 'If True, log debug information.' # --------------------- Session management methods --------------------- # def __init__(self, id=None, **kwargs): self.id_observers = [] self._data = {} for k, v in kwargs.items(): setattr(self, k, v) self.originalid = id self.missing = False if id is None: if self.debug: cherrypy.log('No id given; making a new one', 'TOOLS.SESSIONS') self._regenerate() else: self.id = id if self._exists(): if self.debug: cherrypy.log('Set id to %s.' % id, 'TOOLS.SESSIONS') else: if self.debug: cherrypy.log('Expired or malicious session %r; ' 'making a new one' % id, 'TOOLS.SESSIONS') # Expired or malicious session. Make a new one. # See https://github.com/cherrypy/cherrypy/issues/709. self.id = None self.missing = True self._regenerate() def now(self): """Generate the session specific concept of 'now'. Other session providers can override this to use alternative, possibly timezone aware, versions of 'now'. """ return datetime.datetime.now() def regenerate(self): """Replace the current session (with a new id).""" self.regenerated = True self._regenerate() def _regenerate(self): if self.id is not None: if self.debug: cherrypy.log( 'Deleting the existing session %r before ' 'regeneration.' % self.id, 'TOOLS.SESSIONS') self.delete() old_session_was_locked = self.locked if old_session_was_locked: self.release_lock() if self.debug: cherrypy.log('Old lock released.', 'TOOLS.SESSIONS') self.id = None while self.id is None: self.id = self.generate_id() # Assert that the generated id is not already stored. if self._exists(): self.id = None if self.debug: cherrypy.log('Set id to generated %s.' % self.id, 'TOOLS.SESSIONS') if old_session_was_locked: self.acquire_lock() if self.debug: cherrypy.log('Regenerated lock acquired.', 'TOOLS.SESSIONS') def clean_up(self): """Clean up expired sessions.""" pass def generate_id(self): """Return a new session id.""" return random20() def save(self): """Save session data.""" try: # If session data has never been loaded then it's never been # accessed: no need to save it if self.loaded: t = datetime.timedelta(seconds=self.timeout * 60) expiration_time = self.now() + t if self.debug: cherrypy.log('Saving session %r with expiry %s' % (self.id, expiration_time), 'TOOLS.SESSIONS') self._save(expiration_time) else: if self.debug: cherrypy.log( 'Skipping save of session %r (no session loaded).' % self.id, 'TOOLS.SESSIONS') finally: if self.locked: # Always release the lock if the user didn't release it self.release_lock() if self.debug: cherrypy.log('Lock released after save.', 'TOOLS.SESSIONS') def load(self): """Copy stored session data into this session instance.""" data = self._load() # data is either None or a tuple (session_data, expiration_time) if data is None or data[1] < self.now(): if self.debug: cherrypy.log('Expired session %r, flushing data.' % self.id, 'TOOLS.SESSIONS') self._data = {} else: if self.debug: cherrypy.log('Data loaded for session %r.' % self.id, 'TOOLS.SESSIONS') self._data = data[0] self.loaded = True # Stick the clean_thread in the class, not the instance. # The instances are created and destroyed per-request. cls = self.__class__ if self.clean_freq and not cls.clean_thread: # clean_up is an instancemethod and not a classmethod, # so that tool config can be accessed inside the method. t = cherrypy.process.plugins.Monitor( cherrypy.engine, self.clean_up, self.clean_freq * 60, name='Session cleanup') t.subscribe() cls.clean_thread = t t.start() if self.debug: cherrypy.log('Started cleanup thread.', 'TOOLS.SESSIONS') def delete(self): """Delete stored session data.""" self._delete() if self.debug: cherrypy.log('Deleted session %s.' % self.id, 'TOOLS.SESSIONS') # -------------------- Application accessor methods -------------------- # def __getitem__(self, key): if not self.loaded: self.load() return self._data[key] def __setitem__(self, key, value): if not self.loaded: self.load() self._data[key] = value def __delitem__(self, key): if not self.loaded: self.load() del self._data[key] def pop(self, key, default=missing): """Remove the specified key and return the corresponding value. If key is not found, default is returned if given, otherwise KeyError is raised. """ if not self.loaded: self.load() if default is missing: return self._data.pop(key) else: return self._data.pop(key, default) def __contains__(self, key): if not self.loaded: self.load() return key in self._data if hasattr({}, 'has_key'): def has_key(self, key): """D.has_key(k) -> True if D has a key k, else False.""" if not self.loaded: self.load() return key in self._data def get(self, key, default=None): """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" if not self.loaded: self.load() return self._data.get(key, default) def update(self, d): """D.update(E) -> None. Update D from E: for k in E: D[k] = E[k].""" if not self.loaded: self.load() self._data.update(d) def setdefault(self, key, default=None): """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D.""" if not self.loaded: self.load() return self._data.setdefault(key, default) def clear(self): """D.clear() -> None. Remove all items from D.""" if not self.loaded: self.load() self._data.clear() def keys(self): """D.keys() -> list of D's keys.""" if not self.loaded: self.load() return self._data.keys() def items(self): """D.items() -> list of D's (key, value) pairs, as 2-tuples.""" if not self.loaded: self.load() return self._data.items() def values(self): """D.values() -> list of D's values.""" if not self.loaded: self.load() return self._data.values() class RamSession(Session): # Class-level objects. Don't rebind these! cache = {} locks = {} def clean_up(self): """Clean up expired sessions.""" now = self.now() for _id, (data, expiration_time) in copyitems(self.cache): if expiration_time <= now: try: del self.cache[_id] except KeyError: pass try: if self.locks[_id].acquire(blocking=False): lock = self.locks.pop(_id) lock.release() except KeyError: pass # added to remove obsolete lock objects for _id in list(self.locks): if _id not in self.cache and self.locks[_id].acquire(blocking=False): lock = self.locks.pop(_id) lock.release() def _exists(self): return self.id in self.cache def _load(self): return self.cache.get(self.id) def _save(self, expiration_time): self.cache[self.id] = (self._data, expiration_time) def _delete(self): self.cache.pop(self.id, None) def acquire_lock(self): """Acquire an exclusive lock on the currently-loaded session data.""" self.locked = True self.locks.setdefault(self.id, threading.RLock()).acquire() def release_lock(self): """Release the lock on the currently-loaded session data.""" self.locks[self.id].release() self.locked = False def __len__(self): """Return the number of active sessions.""" return len(self.cache) class FileSession(Session): """Implementation of the File backend for sessions storage_path The folder where session data will be saved. Each session will be saved as pickle.dump(data, expiration_time) in its own file; the filename will be self.SESSION_PREFIX + self.id. lock_timeout A timedelta or numeric seconds indicating how long to block acquiring a lock. If None (default), acquiring a lock will block indefinitely. """ SESSION_PREFIX = 'session-' LOCK_SUFFIX = '.lock' pickle_protocol = pickle.HIGHEST_PROTOCOL def __init__(self, id=None, **kwargs): # The 'storage_path' arg is required for file-based sessions. kwargs['storage_path'] = os.path.abspath(kwargs['storage_path']) kwargs.setdefault('lock_timeout', None) Session.__init__(self, id=id, **kwargs) # validate self.lock_timeout if isinstance(self.lock_timeout, (int, float)): self.lock_timeout = datetime.timedelta(seconds=self.lock_timeout) if not isinstance(self.lock_timeout, (datetime.timedelta, type(None))): raise ValueError('Lock timeout must be numeric seconds or ' 'a timedelta instance.') @classmethod def setup(cls, **kwargs): """Set up the storage system for file-based sessions. This should only be called once per process; this will be done automatically when using sessions.init (as the built-in Tool does). """ # The 'storage_path' arg is required for file-based sessions. kwargs['storage_path'] = os.path.abspath(kwargs['storage_path']) for k, v in kwargs.items(): setattr(cls, k, v) def _get_file_path(self): f = os.path.join(self.storage_path, self.SESSION_PREFIX + self.id) if not os.path.abspath(f).startswith(self.storage_path): raise cherrypy.HTTPError(400, 'Invalid session id in cookie.') return f def _exists(self): path = self._get_file_path() return os.path.exists(path) def _load(self, path=None): assert self.locked, ('The session load without being locked. ' "Check your tools' priority levels.") if path is None: path = self._get_file_path() try: f = open(path, 'rb') try: return pickle.load(f) finally: f.close() except (IOError, EOFError): e = sys.exc_info()[1] if self.debug: cherrypy.log('Error loading the session pickle: %s' % e, 'TOOLS.SESSIONS') return None def _save(self, expiration_time): assert self.locked, ('The session was saved without being locked. ' "Check your tools' priority levels.") f = open(self._get_file_path(), 'wb') try: pickle.dump((self._data, expiration_time), f, self.pickle_protocol) finally: f.close() def _delete(self): assert self.locked, ('The session deletion without being locked. ' "Check your tools' priority levels.") try: os.unlink(self._get_file_path()) except OSError: pass def acquire_lock(self, path=None): """Acquire an exclusive lock on the currently-loaded session data.""" if path is None: path = self._get_file_path() path += self.LOCK_SUFFIX checker = locking.LockChecker(self.id, self.lock_timeout) while not checker.expired(): try: self.lock = lockfile.LockFile(path) except lockfile.LockError: time.sleep(0.1) else: break self.locked = True if self.debug: cherrypy.log('Lock acquired.', 'TOOLS.SESSIONS') def release_lock(self, path=None): """Release the lock on the currently-loaded session data.""" self.lock.release() self.lock.remove() self.locked = False def clean_up(self): """Clean up expired sessions.""" now = self.now() # Iterate over all session files in self.storage_path for fname in os.listdir(self.storage_path): if (fname.startswith(self.SESSION_PREFIX) and not fname.endswith(self.LOCK_SUFFIX)): # We have a session file: lock and load it and check # if it's expired. If it fails, nevermind. path = os.path.join(self.storage_path, fname) self.acquire_lock(path) if self.debug: # This is a bit of a hack, since we're calling clean_up # on the first instance rather than the entire class, # so depending on whether you have "debug" set on the # path of the first session called, this may not run. cherrypy.log('Cleanup lock acquired.', 'TOOLS.SESSIONS') try: contents = self._load(path) # _load returns None on IOError if contents is not None: data, expiration_time = contents if expiration_time < now: # Session expired: deleting it os.unlink(path) finally: self.release_lock(path) def __len__(self): """Return the number of active sessions.""" return len([fname for fname in os.listdir(self.storage_path) if (fname.startswith(self.SESSION_PREFIX) and not fname.endswith(self.LOCK_SUFFIX))]) class MemcachedSession(Session): # The most popular memcached client for Python isn't thread-safe. # Wrap all .get and .set operations in a single lock. mc_lock = threading.RLock() # This is a separate set of locks per session id. locks = {} servers = ['127.0.0.1:11211'] @classmethod def setup(cls, **kwargs): """Set up the storage system for memcached-based sessions. This should only be called once per process; this will be done automatically when using sessions.init (as the built-in Tool does). """ for k, v in kwargs.items(): setattr(cls, k, v) import memcache cls.cache = memcache.Client(cls.servers) def _exists(self): self.mc_lock.acquire() try: return bool(self.cache.get(self.id)) finally: self.mc_lock.release() def _load(self): self.mc_lock.acquire() try: return self.cache.get(self.id) finally: self.mc_lock.release() def _save(self, expiration_time): # Send the expiration time as "Unix time" (seconds since 1/1/1970) td = int(time.mktime(expiration_time.timetuple())) self.mc_lock.acquire() try: if not self.cache.set(self.id, (self._data, expiration_time), td): raise AssertionError( 'Session data for id %r not set.' % self.id) finally: self.mc_lock.release() def _delete(self): self.cache.delete(self.id) def acquire_lock(self): """Acquire an exclusive lock on the currently-loaded session data.""" self.locked = True self.locks.setdefault(self.id, threading.RLock()).acquire() if self.debug: cherrypy.log('Lock acquired.', 'TOOLS.SESSIONS') def release_lock(self): """Release the lock on the currently-loaded session data.""" self.locks[self.id].release() self.locked = False def __len__(self): """Return the number of active sessions.""" raise NotImplementedError # Hook functions (for CherryPy tools) def save(): """Save any changed session data.""" if not hasattr(cherrypy.serving, 'session'): return request = cherrypy.serving.request response = cherrypy.serving.response # Guard against running twice if hasattr(request, '_sessionsaved'): return request._sessionsaved = True if response.stream: # If the body is being streamed, we have to save the data # *after* the response has been written out request.hooks.attach('on_end_request', cherrypy.session.save) else: # If the body is not being streamed, we save the data now # (so we can release the lock). if is_iterator(response.body): response.collapse_body() cherrypy.session.save() save.failsafe = True def close(): """Close the session object for this request.""" sess = getattr(cherrypy.serving, 'session', None) if getattr(sess, 'locked', False): # If the session is still locked we release the lock sess.release_lock() if sess.debug: cherrypy.log('Lock released on close.', 'TOOLS.SESSIONS') close.failsafe = True close.priority = 90 def init(storage_type=None, path=None, path_header=None, name='session_id', timeout=60, domain=None, secure=False, clean_freq=5, persistent=True, httponly=False, debug=False, # Py27 compat # *, storage_class=RamSession, **kwargs): """Initialize session object (using cookies). storage_class The Session subclass to use. Defaults to RamSession. storage_type (deprecated) One of 'ram', 'file', memcached'. This will be used to look up the corresponding class in cherrypy.lib.sessions globals. For example, 'file' will use the FileSession class. path The 'path' value to stick in the response cookie metadata. path_header If 'path' is None (the default), then the response cookie 'path' will be pulled from request.headers[path_header]. name The name of the cookie. timeout The expiration timeout (in minutes) for the stored session data. If 'persistent' is True (the default), this is also the timeout for the cookie. domain The cookie domain. secure If False (the default) the cookie 'secure' value will not be set. If True, the cookie 'secure' value will be set (to 1). clean_freq (minutes) The poll rate for expired session cleanup. persistent If True (the default), the 'timeout' argument will be used to expire the cookie. If False, the cookie will not have an expiry, and the cookie will be a "session cookie" which expires when the browser is closed. httponly If False (the default) the cookie 'httponly' value will not be set. If True, the cookie 'httponly' value will be set (to 1). Any additional kwargs will be bound to the new Session instance, and may be specific to the storage type. See the subclass of Session you're using for more information. """ # Py27 compat storage_class = kwargs.pop('storage_class', RamSession) request = cherrypy.serving.request # Guard against running twice if hasattr(request, '_session_init_flag'): return request._session_init_flag = True # Check if request came with a session ID id = None if name in request.cookie: id = request.cookie[name].value if debug: cherrypy.log('ID obtained from request.cookie: %r' % id, 'TOOLS.SESSIONS') first_time = not hasattr(cherrypy, 'session') if storage_type: if first_time: msg = 'storage_type is deprecated. Supply storage_class instead' cherrypy.log(msg) storage_class = storage_type.title() + 'Session' storage_class = globals()[storage_class] # call setup first time only if first_time: if hasattr(storage_class, 'setup'): storage_class.setup(**kwargs) # Create and attach a new Session instance to cherrypy.serving. # It will possess a reference to (and lock, and lazily load) # the requested session data. kwargs['timeout'] = timeout kwargs['clean_freq'] = clean_freq cherrypy.serving.session = sess = storage_class(id, **kwargs) sess.debug = debug def update_cookie(id): """Update the cookie every time the session id changes.""" cherrypy.serving.response.cookie[name] = id sess.id_observers.append(update_cookie) # Create cherrypy.session which will proxy to cherrypy.serving.session if not hasattr(cherrypy, 'session'): cherrypy.session = cherrypy._ThreadLocalProxy('session') if persistent: cookie_timeout = timeout else: # See http://support.microsoft.com/kb/223799/EN-US/ # and http://support.mozilla.com/en-US/kb/Cookies cookie_timeout = None set_response_cookie(path=path, path_header=path_header, name=name, timeout=cookie_timeout, domain=domain, secure=secure, httponly=httponly) def set_response_cookie(path=None, path_header=None, name='session_id', timeout=60, domain=None, secure=False, httponly=False): """Set a response cookie for the client. path the 'path' value to stick in the response cookie metadata. path_header if 'path' is None (the default), then the response cookie 'path' will be pulled from request.headers[path_header]. name the name of the cookie. timeout the expiration timeout for the cookie. If 0 or other boolean False, no 'expires' param will be set, and the cookie will be a "session cookie" which expires when the browser is closed. domain the cookie domain. secure if False (the default) the cookie 'secure' value will not be set. If True, the cookie 'secure' value will be set (to 1). httponly If False (the default) the cookie 'httponly' value will not be set. If True, the cookie 'httponly' value will be set (to 1). """ # Set response cookie cookie = cherrypy.serving.response.cookie cookie[name] = cherrypy.serving.session.id cookie[name]['path'] = ( path or cherrypy.serving.request.headers.get(path_header) or '/' ) # We'd like to use the "max-age" param as indicated in # http://www.faqs.org/rfcs/rfc2109.html but IE doesn't # save it to disk and the session is lost if people close # the browser. So we have to use the old "expires" ... sigh ... ## cookie[name]['max-age'] = timeout * 60 if timeout: e = time.time() + (timeout * 60) cookie[name]['expires'] = httputil.HTTPDate(e) if domain is not None: cookie[name]['domain'] = domain if secure: cookie[name]['secure'] = 1 if httponly: if not cookie[name].isReservedKey('httponly'): raise ValueError('The httponly cookie token is not supported.') cookie[name]['httponly'] = 1 def expire(): """Expire the current session cookie.""" name = cherrypy.serving.request.config.get( 'tools.sessions.name', 'session_id') one_year = 60 * 60 * 24 * 365 e = time.time() - one_year cherrypy.serving.response.cookie[name]['expires'] = httputil.HTTPDate(e) SABnzbd-2.3.2/cherrypy/lib/static.py0000644000000000000000000003516013217005257015412 0ustar 00000000000000import os import re import stat import mimetypes try: from io import UnsupportedOperation except ImportError: UnsupportedOperation = object() import cherrypy from cherrypy._cpcompat import ntob, unquote from cherrypy.lib import cptools, httputil, file_generator_limited mimetypes.init() mimetypes.types_map['.dwg'] = 'image/x-dwg' mimetypes.types_map['.ico'] = 'image/x-icon' mimetypes.types_map['.bz2'] = 'application/x-bzip2' mimetypes.types_map['.gz'] = 'application/x-gzip' def serve_file(path, content_type=None, disposition=None, name=None, debug=False): """Set status, headers, and body in order to serve the given path. The Content-Type header will be set to the content_type arg, if provided. If not provided, the Content-Type will be guessed by the file extension of the 'path' argument. If disposition is not None, the Content-Disposition header will be set to "; filename=". If name is None, it will be set to the basename of path. If disposition is None, no Content-Disposition header will be written. """ response = cherrypy.serving.response # If path is relative, users should fix it by making path absolute. # That is, CherryPy should not guess where the application root is. # It certainly should *not* use cwd (since CP may be invoked from a # variety of paths). If using tools.staticdir, you can make your relative # paths become absolute by supplying a value for "tools.staticdir.root". if not os.path.isabs(path): msg = "'%s' is not an absolute path." % path if debug: cherrypy.log(msg, 'TOOLS.STATICFILE') raise ValueError(msg) try: st = os.stat(path) except (OSError, TypeError, ValueError): # OSError when file fails to stat # TypeError on Python 2 when there's a null byte # ValueError on Python 3 when there's a null byte if debug: cherrypy.log('os.stat(%r) failed' % path, 'TOOLS.STATIC') raise cherrypy.NotFound() # Check if path is a directory. if stat.S_ISDIR(st.st_mode): # Let the caller deal with it as they like. if debug: cherrypy.log('%r is a directory' % path, 'TOOLS.STATIC') raise cherrypy.NotFound() # Set the Last-Modified response header, so that # modified-since validation code can work. response.headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime) cptools.validate_since() if content_type is None: # Set content-type based on filename extension ext = '' i = path.rfind('.') if i != -1: ext = path[i:].lower() content_type = mimetypes.types_map.get(ext, None) if content_type is not None: response.headers['Content-Type'] = content_type if debug: cherrypy.log('Content-Type: %r' % content_type, 'TOOLS.STATIC') cd = None if disposition is not None: if name is None: name = os.path.basename(path) cd = '%s; filename="%s"' % (disposition, name) response.headers['Content-Disposition'] = cd if debug: cherrypy.log('Content-Disposition: %r' % cd, 'TOOLS.STATIC') # Set Content-Length and use an iterable (file object) # this way CP won't load the whole file in memory content_length = st.st_size fileobj = open(path, 'rb') return _serve_fileobj(fileobj, content_type, content_length, debug=debug) def serve_fileobj(fileobj, content_type=None, disposition=None, name=None, debug=False): """Set status, headers, and body in order to serve the given file object. The Content-Type header will be set to the content_type arg, if provided. If disposition is not None, the Content-Disposition header will be set to "; filename=". If name is None, 'filename' will not be set. If disposition is None, no Content-Disposition header will be written. CAUTION: If the request contains a 'Range' header, one or more seek()s will be performed on the file object. This may cause undesired behavior if the file object is not seekable. It could also produce undesired results if the caller set the read position of the file object prior to calling serve_fileobj(), expecting that the data would be served starting from that position. """ response = cherrypy.serving.response try: st = os.fstat(fileobj.fileno()) except AttributeError: if debug: cherrypy.log('os has no fstat attribute', 'TOOLS.STATIC') content_length = None except UnsupportedOperation: content_length = None else: # Set the Last-Modified response header, so that # modified-since validation code can work. response.headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime) cptools.validate_since() content_length = st.st_size if content_type is not None: response.headers['Content-Type'] = content_type if debug: cherrypy.log('Content-Type: %r' % content_type, 'TOOLS.STATIC') cd = None if disposition is not None: if name is None: cd = disposition else: cd = '%s; filename="%s"' % (disposition, name) response.headers['Content-Disposition'] = cd if debug: cherrypy.log('Content-Disposition: %r' % cd, 'TOOLS.STATIC') return _serve_fileobj(fileobj, content_type, content_length, debug=debug) def _serve_fileobj(fileobj, content_type, content_length, debug=False): """Internal. Set response.body to the given file object, perhaps ranged.""" response = cherrypy.serving.response # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code request = cherrypy.serving.request if request.protocol >= (1, 1): response.headers['Accept-Ranges'] = 'bytes' r = httputil.get_ranges(request.headers.get('Range'), content_length) if r == []: response.headers['Content-Range'] = 'bytes */%s' % content_length message = ('Invalid Range (first-byte-pos greater than ' 'Content-Length)') if debug: cherrypy.log(message, 'TOOLS.STATIC') raise cherrypy.HTTPError(416, message) if r: if len(r) == 1: # Return a single-part response. start, stop = r[0] if stop > content_length: stop = content_length r_len = stop - start if debug: cherrypy.log( 'Single part; start: %r, stop: %r' % (start, stop), 'TOOLS.STATIC') response.status = '206 Partial Content' response.headers['Content-Range'] = ( 'bytes %s-%s/%s' % (start, stop - 1, content_length)) response.headers['Content-Length'] = r_len fileobj.seek(start) response.body = file_generator_limited(fileobj, r_len) else: # Return a multipart/byteranges response. response.status = '206 Partial Content' try: # Python 3 from email.generator import _make_boundary as make_boundary except ImportError: # Python 2 from mimetools import choose_boundary as make_boundary boundary = make_boundary() ct = 'multipart/byteranges; boundary=%s' % boundary response.headers['Content-Type'] = ct if 'Content-Length' in response.headers: # Delete Content-Length header so finalize() recalcs it. del response.headers['Content-Length'] def file_ranges(): # Apache compatibility: yield ntob('\r\n') for start, stop in r: if debug: cherrypy.log( 'Multipart; start: %r, stop: %r' % ( start, stop), 'TOOLS.STATIC') yield ntob('--' + boundary, 'ascii') yield ntob('\r\nContent-type: %s' % content_type, 'ascii') yield ntob( '\r\nContent-range: bytes %s-%s/%s\r\n\r\n' % ( start, stop - 1, content_length), 'ascii') fileobj.seek(start) gen = file_generator_limited(fileobj, stop - start) for chunk in gen: yield chunk yield ntob('\r\n') # Final boundary yield ntob('--' + boundary + '--', 'ascii') # Apache compatibility: yield ntob('\r\n') response.body = file_ranges() return response.body else: if debug: cherrypy.log('No byteranges requested', 'TOOLS.STATIC') # Set Content-Length and use an iterable (file object) # this way CP won't load the whole file in memory response.headers['Content-Length'] = content_length response.body = fileobj return response.body def serve_download(path, name=None): """Serve 'path' as an application/x-download attachment.""" # This is such a common idiom I felt it deserved its own wrapper. return serve_file(path, 'application/x-download', 'attachment', name) def _attempt(filename, content_types, debug=False): if debug: cherrypy.log('Attempting %r (content_types %r)' % (filename, content_types), 'TOOLS.STATICDIR') try: # you can set the content types for a # complete directory per extension content_type = None if content_types: r, ext = os.path.splitext(filename) content_type = content_types.get(ext[1:], None) serve_file(filename, content_type=content_type, debug=debug) return True except cherrypy.NotFound: # If we didn't find the static file, continue handling the # request. We might find a dynamic handler instead. if debug: cherrypy.log('NotFound', 'TOOLS.STATICFILE') return False def staticdir(section, dir, root='', match='', content_types=None, index='', debug=False): """Serve a static resource from the given (root +) dir. match If given, request.path_info will be searched for the given regular expression before attempting to serve static content. content_types If given, it should be a Python dictionary of {file-extension: content-type} pairs, where 'file-extension' is a string (e.g. "gif") and 'content-type' is the value to write out in the Content-Type response header (e.g. "image/gif"). index If provided, it should be the (relative) name of a file to serve for directory requests. For example, if the dir argument is '/home/me', the Request-URI is 'myapp', and the index arg is 'index.html', the file '/home/me/myapp/index.html' will be sought. """ request = cherrypy.serving.request if request.method not in ('GET', 'HEAD'): if debug: cherrypy.log('request.method not GET or HEAD', 'TOOLS.STATICDIR') return False if match and not re.search(match, request.path_info): if debug: cherrypy.log('request.path_info %r does not match pattern %r' % (request.path_info, match), 'TOOLS.STATICDIR') return False # Allow the use of '~' to refer to a user's home directory. dir = os.path.expanduser(dir) # If dir is relative, make absolute using "root". if not os.path.isabs(dir): if not root: msg = 'Static dir requires an absolute dir (or root).' if debug: cherrypy.log(msg, 'TOOLS.STATICDIR') raise ValueError(msg) dir = os.path.join(root, dir) # Determine where we are in the object tree relative to 'section' # (where the static tool was defined). if section == 'global': section = '/' section = section.rstrip(r'\/') branch = request.path_info[len(section) + 1:] branch = unquote(branch.lstrip(r'\/')) # If branch is "", filename will end in a slash filename = os.path.join(dir, branch) if debug: cherrypy.log('Checking file %r to fulfill %r' % (filename, request.path_info), 'TOOLS.STATICDIR') # There's a chance that the branch pulled from the URL might # have ".." or similar uplevel attacks in it. Check that the final # filename is a child of dir. if not os.path.normpath(filename).startswith(os.path.normpath(dir)): raise cherrypy.HTTPError(403) # Forbidden handled = _attempt(filename, content_types) if not handled: # Check for an index file if a folder was requested. if index: handled = _attempt(os.path.join(filename, index), content_types) if handled: request.is_index = filename[-1] in (r'\/') return handled def staticfile(filename, root=None, match='', content_types=None, debug=False): """Serve a static resource from the given (root +) filename. match If given, request.path_info will be searched for the given regular expression before attempting to serve static content. content_types If given, it should be a Python dictionary of {file-extension: content-type} pairs, where 'file-extension' is a string (e.g. "gif") and 'content-type' is the value to write out in the Content-Type response header (e.g. "image/gif"). """ request = cherrypy.serving.request if request.method not in ('GET', 'HEAD'): if debug: cherrypy.log('request.method not GET or HEAD', 'TOOLS.STATICFILE') return False if match and not re.search(match, request.path_info): if debug: cherrypy.log('request.path_info %r does not match pattern %r' % (request.path_info, match), 'TOOLS.STATICFILE') return False # If filename is relative, make absolute using "root". if not os.path.isabs(filename): if not root: msg = "Static tool requires an absolute filename (got '%s')." % ( filename,) if debug: cherrypy.log(msg, 'TOOLS.STATICFILE') raise ValueError(msg) filename = os.path.join(root, filename) return _attempt(filename, content_types, debug=debug) SABnzbd-2.3.2/cherrypy/lib/xmlrpcutil.py0000644000000000000000000000311013217005257016314 0ustar 00000000000000import sys import cherrypy from cherrypy._cpcompat import ntob def get_xmlrpclib(): try: import xmlrpc.client as x except ImportError: import xmlrpclib as x return x def process_body(): """Return (params, method) from request body.""" try: return get_xmlrpclib().loads(cherrypy.request.body.read()) except Exception: return ('ERROR PARAMS', ), 'ERRORMETHOD' def patched_path(path): """Return 'path', doctored for RPC.""" if not path.endswith('/'): path += '/' if path.startswith('/RPC2/'): # strip the first /rpc2 path = path[5:] return path def _set_response(body): # The XML-RPC spec (http://www.xmlrpc.com/spec) says: # "Unless there's a lower-level error, always return 200 OK." # Since Python's xmlrpclib interprets a non-200 response # as a "Protocol Error", we'll just return 200 every time. response = cherrypy.response response.status = '200 OK' response.body = ntob(body, 'utf-8') response.headers['Content-Type'] = 'text/xml' response.headers['Content-Length'] = len(body) def respond(body, encoding='utf-8', allow_none=0): xmlrpclib = get_xmlrpclib() if not isinstance(body, xmlrpclib.Fault): body = (body,) _set_response(xmlrpclib.dumps(body, methodresponse=1, encoding=encoding, allow_none=allow_none)) def on_error(*args, **kwargs): body = str(sys.exc_info()[1]) xmlrpclib = get_xmlrpclib() _set_response(xmlrpclib.dumps(xmlrpclib.Fault(1, body))) SABnzbd-2.3.2/cherrypy/lib/__init__.py0000644000000000000000000000451513217005257015662 0ustar 00000000000000"""CherryPy Library""" def is_iterator(obj): '''Returns a boolean indicating if the object provided implements the iterator protocol (i.e. like a generator). This will return false for objects which iterable, but not iterators themselves.''' from types import GeneratorType if isinstance(obj, GeneratorType): return True elif not hasattr(obj, '__iter__'): return False else: # Types which implement the protocol must return themselves when # invoking 'iter' upon them. return iter(obj) is obj def is_closable_iterator(obj): # Not an iterator. if not is_iterator(obj): return False # A generator - the easiest thing to deal with. import inspect if inspect.isgenerator(obj): return True # A custom iterator. Look for a close method... if not (hasattr(obj, 'close') and callable(obj.close)): return False # ... which doesn't require any arguments. try: inspect.getcallargs(obj.close) except TypeError: return False else: return True class file_generator(object): """Yield the given input (a file object) in chunks (default 64k). (Core)""" def __init__(self, input, chunkSize=65536): self.input = input self.chunkSize = chunkSize def __iter__(self): return self def __next__(self): chunk = self.input.read(self.chunkSize) if chunk: return chunk else: if hasattr(self.input, 'close'): self.input.close() raise StopIteration() next = __next__ def file_generator_limited(fileobj, count, chunk_size=65536): """Yield the given file object in chunks, stopping after `count` bytes has been emitted. Default chunk size is 64kB. (Core) """ remaining = count while remaining > 0: chunk = fileobj.read(min(chunk_size, remaining)) chunklen = len(chunk) if chunklen == 0: return remaining -= chunklen yield chunk def set_vary_header(response, header_name): 'Add a Vary header to a response' varies = response.headers.get('Vary', '') varies = [x.strip() for x in varies.split(',') if x.strip()] if header_name not in varies: varies.append(header_name) response.headers['Vary'] = ', '.join(varies) SABnzbd-2.3.2/cherrypy/process/plugins.py0000644000000000000000000006375613217005257016530 0ustar 00000000000000"""Site services for use with a Web Site Process Bus.""" import os import re import signal as _signal import sys import time import threading from cherrypy._cpcompat import text_or_bytes, get_thread_ident from cherrypy._cpcompat import ntob, Timer # _module__file__base is used by Autoreload to make # absolute any filenames retrieved from sys.modules which are not # already absolute paths. This is to work around Python's quirk # of importing the startup script and using a relative filename # for it in sys.modules. # # Autoreload examines sys.modules afresh every time it runs. If an application # changes the current directory by executing os.chdir(), then the next time # Autoreload runs, it will not be able to find any filenames which are # not absolute paths, because the current directory is not the same as when the # module was first imported. Autoreload will then wrongly conclude the file # has "changed", and initiate the shutdown/re-exec sequence. # See ticket #917. # For this workaround to have a decent probability of success, this module # needs to be imported as early as possible, before the app has much chance # to change the working directory. _module__file__base = os.getcwd() class SimplePlugin(object): """Plugin base class which auto-subscribes methods for known channels.""" bus = None """A :class:`Bus `, usually cherrypy.engine. """ def __init__(self, bus): self.bus = bus def subscribe(self): """Register this object as a (multi-channel) listener on the bus.""" for channel in self.bus.listeners: # Subscribe self.start, self.exit, etc. if present. method = getattr(self, channel, None) if method is not None: self.bus.subscribe(channel, method) def unsubscribe(self): """Unregister this object as a listener on the bus.""" for channel in self.bus.listeners: # Unsubscribe self.start, self.exit, etc. if present. method = getattr(self, channel, None) if method is not None: self.bus.unsubscribe(channel, method) class SignalHandler(object): """Register bus channels (and listeners) for system signals. You can modify what signals your application listens for, and what it does when it receives signals, by modifying :attr:`SignalHandler.handlers`, a dict of {signal name: callback} pairs. The default set is:: handlers = {'SIGTERM': self.bus.exit, 'SIGHUP': self.handle_SIGHUP, 'SIGUSR1': self.bus.graceful, } The :func:`SignalHandler.handle_SIGHUP`` method calls :func:`bus.restart()` if the process is daemonized, but :func:`bus.exit()` if the process is attached to a TTY. This is because Unix window managers tend to send SIGHUP to terminal windows when the user closes them. Feel free to add signals which are not available on every platform. The :class:`SignalHandler` will ignore errors raised from attempting to register handlers for unknown signals. """ handlers = {} """A map from signal names (e.g. 'SIGTERM') to handlers (e.g. bus.exit).""" signals = {} """A map from signal numbers to names.""" for k, v in vars(_signal).items(): if k.startswith('SIG') and not k.startswith('SIG_'): signals[v] = k del k, v def __init__(self, bus): self.bus = bus # Set default handlers self.handlers = {'SIGTERM': self.bus.exit, 'SIGHUP': self.handle_SIGHUP, 'SIGUSR1': self.bus.graceful, } if sys.platform[:4] == 'java': del self.handlers['SIGUSR1'] self.handlers['SIGUSR2'] = self.bus.graceful self.bus.log('SIGUSR1 cannot be set on the JVM platform. ' 'Using SIGUSR2 instead.') self.handlers['SIGINT'] = self._jython_SIGINT_handler self._previous_handlers = {} # used to determine is the process is a daemon in `self._is_daemonized` self._original_pid = os.getpid() def _jython_SIGINT_handler(self, signum=None, frame=None): # See http://bugs.jython.org/issue1313 self.bus.log('Keyboard Interrupt: shutting down bus') self.bus.exit() def _is_daemonized(self): """Return boolean indicating if the current process is running as a daemon. The criteria to determine the `daemon` condition is to verify if the current pid is not the same as the one that got used on the initial construction of the plugin *and* the stdin is not connected to a terminal. The sole validation of the tty is not enough when the plugin is executing inside other process like in a CI tool (Buildbot, Jenkins). """ if (self._original_pid != os.getpid() and not os.isatty(sys.stdin.fileno())): return True else: return False def subscribe(self): """Subscribe self.handlers to signals.""" for sig, func in self.handlers.items(): try: self.set_handler(sig, func) except ValueError: pass def unsubscribe(self): """Unsubscribe self.handlers from signals.""" for signum, handler in self._previous_handlers.items(): signame = self.signals[signum] if handler is None: self.bus.log('Restoring %s handler to SIG_DFL.' % signame) handler = _signal.SIG_DFL else: self.bus.log('Restoring %s handler %r.' % (signame, handler)) try: our_handler = _signal.signal(signum, handler) if our_handler is None: self.bus.log('Restored old %s handler %r, but our ' 'handler was not registered.' % (signame, handler), level=30) except ValueError: self.bus.log('Unable to restore %s handler %r.' % (signame, handler), level=40, traceback=True) def set_handler(self, signal, listener=None): """Subscribe a handler for the given signal (number or name). If the optional 'listener' argument is provided, it will be subscribed as a listener for the given signal's channel. If the given signal name or number is not available on the current platform, ValueError is raised. """ if isinstance(signal, text_or_bytes): signum = getattr(_signal, signal, None) if signum is None: raise ValueError('No such signal: %r' % signal) signame = signal else: try: signame = self.signals[signal] except KeyError: raise ValueError('No such signal: %r' % signal) signum = signal prev = _signal.signal(signum, self._handle_signal) self._previous_handlers[signum] = prev if listener is not None: self.bus.log('Listening for %s.' % signame) self.bus.subscribe(signame, listener) def _handle_signal(self, signum=None, frame=None): """Python signal handler (self.set_handler subscribes it for you).""" signame = self.signals[signum] self.bus.log('Caught signal %s.' % signame) self.bus.publish(signame) def handle_SIGHUP(self): """Restart if daemonized, else exit.""" if self._is_daemonized(): self.bus.log('SIGHUP caught while daemonized. Restarting.') self.bus.restart() else: # not daemonized (may be foreground or background) self.bus.log('SIGHUP caught but not daemonized. Exiting.') self.bus.exit() try: import pwd import grp except ImportError: pwd, grp = None, None class DropPrivileges(SimplePlugin): """Drop privileges. uid/gid arguments not available on Windows. Special thanks to `Gavin Baker `_ """ def __init__(self, bus, umask=None, uid=None, gid=None): SimplePlugin.__init__(self, bus) self.finalized = False self.uid = uid self.gid = gid self.umask = umask def _get_uid(self): return self._uid def _set_uid(self, val): if val is not None: if pwd is None: self.bus.log('pwd module not available; ignoring uid.', level=30) val = None elif isinstance(val, text_or_bytes): val = pwd.getpwnam(val)[2] self._uid = val uid = property(_get_uid, _set_uid, doc='The uid under which to run. Availability: Unix.') def _get_gid(self): return self._gid def _set_gid(self, val): if val is not None: if grp is None: self.bus.log('grp module not available; ignoring gid.', level=30) val = None elif isinstance(val, text_or_bytes): val = grp.getgrnam(val)[2] self._gid = val gid = property(_get_gid, _set_gid, doc='The gid under which to run. Availability: Unix.') def _get_umask(self): return self._umask def _set_umask(self, val): if val is not None: try: os.umask except AttributeError: self.bus.log('umask function not available; ignoring umask.', level=30) val = None self._umask = val umask = property( _get_umask, _set_umask, doc="""The default permission mode for newly created files and directories. Usually expressed in octal format, for example, ``0644``. Availability: Unix, Windows. """) def start(self): # uid/gid def current_ids(): """Return the current (uid, gid) if available.""" name, group = None, None if pwd: name = pwd.getpwuid(os.getuid())[0] if grp: group = grp.getgrgid(os.getgid())[0] return name, group if self.finalized: if not (self.uid is None and self.gid is None): self.bus.log('Already running as uid: %r gid: %r' % current_ids()) else: if self.uid is None and self.gid is None: if pwd or grp: self.bus.log('uid/gid not set', level=30) else: self.bus.log('Started as uid: %r gid: %r' % current_ids()) if self.gid is not None: os.setgid(self.gid) os.setgroups([]) if self.uid is not None: os.setuid(self.uid) self.bus.log('Running as uid: %r gid: %r' % current_ids()) # umask if self.finalized: if self.umask is not None: self.bus.log('umask already set to: %03o' % self.umask) else: if self.umask is None: self.bus.log('umask not set', level=30) else: old_umask = os.umask(self.umask) self.bus.log('umask old: %03o, new: %03o' % (old_umask, self.umask)) self.finalized = True # This is slightly higher than the priority for server.start # in order to facilitate the most common use: starting on a low # port (which requires root) and then dropping to another user. start.priority = 77 class Daemonizer(SimplePlugin): """Daemonize the running script. Use this with a Web Site Process Bus via:: Daemonizer(bus).subscribe() When this component finishes, the process is completely decoupled from the parent environment. Please note that when this component is used, the return code from the parent process will still be 0 if a startup error occurs in the forked children. Errors in the initial daemonizing process still return proper exit codes. Therefore, if you use this plugin to daemonize, don't use the return code as an accurate indicator of whether the process fully started. In fact, that return code only indicates if the process succesfully finished the first fork. """ def __init__(self, bus, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): SimplePlugin.__init__(self, bus) self.stdin = stdin self.stdout = stdout self.stderr = stderr self.finalized = False def start(self): if self.finalized: self.bus.log('Already deamonized.') # forking has issues with threads: # http://www.opengroup.org/onlinepubs/000095399/functions/fork.html # "The general problem with making fork() work in a multi-threaded # world is what to do with all of the threads..." # So we check for active threads: if threading.activeCount() != 1: self.bus.log('There are %r active threads. ' 'Daemonizing now may cause strange failures.' % threading.enumerate(), level=30) # See http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 # (or http://www.faqs.org/faqs/unix-faq/programmer/faq/ section 1.7) # and http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012 # Finish up with the current stdout/stderr sys.stdout.flush() sys.stderr.flush() # Do first fork. try: pid = os.fork() if pid == 0: # This is the child process. Continue. pass else: # This is the first parent. Exit, now that we've forked. self.bus.log('Forking once.') os._exit(0) except OSError: # Python raises OSError rather than returning negative numbers. exc = sys.exc_info()[1] sys.exit('%s: fork #1 failed: (%d) %s\n' % (sys.argv[0], exc.errno, exc.strerror)) os.setsid() # Do second fork try: pid = os.fork() if pid > 0: self.bus.log('Forking twice.') os._exit(0) # Exit second parent except OSError: exc = sys.exc_info()[1] sys.exit('%s: fork #2 failed: (%d) %s\n' % (sys.argv[0], exc.errno, exc.strerror)) os.chdir('/') os.umask(0) si = open(self.stdin, 'r') so = open(self.stdout, 'a+') se = open(self.stderr, 'a+') # os.dup2(fd, fd2) will close fd2 if necessary, # so we don't explicitly close stdin/out/err. # See http://docs.python.org/lib/os-fd-ops.html os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) self.bus.log('Daemonized to PID: %s' % os.getpid()) self.finalized = True start.priority = 65 class PIDFile(SimplePlugin): """Maintain a PID file via a WSPBus.""" def __init__(self, bus, pidfile): SimplePlugin.__init__(self, bus) self.pidfile = pidfile self.finalized = False def start(self): pid = os.getpid() if self.finalized: self.bus.log('PID %r already written to %r.' % (pid, self.pidfile)) else: open(self.pidfile, 'wb').write(ntob('%s\n' % pid, 'utf8')) self.bus.log('PID %r written to %r.' % (pid, self.pidfile)) self.finalized = True start.priority = 70 def exit(self): try: os.remove(self.pidfile) self.bus.log('PID file removed: %r.' % self.pidfile) except (KeyboardInterrupt, SystemExit): raise except: pass class PerpetualTimer(Timer): """A responsive subclass of threading.Timer whose run() method repeats. Use this timer only when you really need a very interruptible timer; this checks its 'finished' condition up to 20 times a second, which can results in pretty high CPU usage """ def __init__(self, *args, **kwargs): "Override parent constructor to allow 'bus' to be provided." self.bus = kwargs.pop('bus', None) super(PerpetualTimer, self).__init__(*args, **kwargs) def run(self): while True: self.finished.wait(self.interval) if self.finished.isSet(): return try: self.function(*self.args, **self.kwargs) except Exception: if self.bus: self.bus.log( 'Error in perpetual timer thread function %r.' % self.function, level=40, traceback=True) # Quit on first error to avoid massive logs. raise class BackgroundTask(threading.Thread): """A subclass of threading.Thread whose run() method repeats. Use this class for most repeating tasks. It uses time.sleep() to wait for each interval, which isn't very responsive; that is, even if you call self.cancel(), you'll have to wait until the sleep() call finishes before the thread stops. To compensate, it defaults to being daemonic, which means it won't delay stopping the whole process. """ def __init__(self, interval, function, args=[], kwargs={}, bus=None): super(BackgroundTask, self).__init__() self.interval = interval self.function = function self.args = args self.kwargs = kwargs self.running = False self.bus = bus # default to daemonic self.daemon = True def cancel(self): self.running = False def run(self): self.running = True while self.running: time.sleep(self.interval) if not self.running: return try: self.function(*self.args, **self.kwargs) except Exception: if self.bus: self.bus.log('Error in background task thread function %r.' % self.function, level=40, traceback=True) # Quit on first error to avoid massive logs. raise class Monitor(SimplePlugin): """WSPBus listener to periodically run a callback in its own thread.""" callback = None """The function to call at intervals.""" frequency = 60 """The time in seconds between callback runs.""" thread = None """A :class:`BackgroundTask` thread. """ def __init__(self, bus, callback, frequency=60, name=None): SimplePlugin.__init__(self, bus) self.callback = callback self.frequency = frequency self.thread = None self.name = name def start(self): """Start our callback in its own background thread.""" if self.frequency > 0: threadname = self.name or self.__class__.__name__ if self.thread is None: self.thread = BackgroundTask(self.frequency, self.callback, bus=self.bus) self.thread.setName(threadname) self.thread.start() self.bus.log('Started monitor thread %r.' % threadname) else: self.bus.log('Monitor thread %r already started.' % threadname) start.priority = 70 def stop(self): """Stop our callback's background task thread.""" if self.thread is None: self.bus.log('No thread running for %s.' % self.name or self.__class__.__name__) else: if self.thread is not threading.currentThread(): name = self.thread.getName() self.thread.cancel() if not self.thread.daemon: self.bus.log('Joining %r' % name) self.thread.join() self.bus.log('Stopped thread %r.' % name) self.thread = None def graceful(self): """Stop the callback's background task thread and restart it.""" self.stop() self.start() class Autoreloader(Monitor): """Monitor which re-executes the process when files change. This :ref:`plugin` restarts the process (via :func:`os.execv`) if any of the files it monitors change (or is deleted). By default, the autoreloader monitors all imported modules; you can add to the set by adding to ``autoreload.files``:: cherrypy.engine.autoreload.files.add(myFile) If there are imported files you do *not* wish to monitor, you can adjust the ``match`` attribute, a regular expression. For example, to stop monitoring cherrypy itself:: cherrypy.engine.autoreload.match = r'^(?!cherrypy).+' Like all :class:`Monitor` plugins, the autoreload plugin takes a ``frequency`` argument. The default is 1 second; that is, the autoreloader will examine files once each second. """ files = None """The set of files to poll for modifications.""" frequency = 1 """The interval in seconds at which to poll for modified files.""" match = '.*' """A regular expression by which to match filenames.""" def __init__(self, bus, frequency=1, match='.*'): self.mtimes = {} self.files = set() self.match = match Monitor.__init__(self, bus, self.run, frequency) def start(self): """Start our own background task thread for self.run.""" if self.thread is None: self.mtimes = {} Monitor.start(self) start.priority = 70 def sysfiles(self): """Return a Set of sys.modules filenames to monitor.""" files = set() for k, m in list(sys.modules.items()): if re.match(self.match, k): if ( hasattr(m, '__loader__') and hasattr(m.__loader__, 'archive') ): f = m.__loader__.archive else: f = getattr(m, '__file__', None) if f is not None and not os.path.isabs(f): # ensure absolute paths so a os.chdir() in the app # doesn't break me f = os.path.normpath( os.path.join(_module__file__base, f)) files.add(f) return files def run(self): """Reload the process if registered files have been modified.""" for filename in self.sysfiles() | self.files: if filename: if filename.endswith('.pyc'): filename = filename[:-1] oldtime = self.mtimes.get(filename, 0) if oldtime is None: # Module with no .py file. Skip it. continue try: mtime = os.stat(filename).st_mtime except OSError: # Either a module with no .py file, or it's been deleted. mtime = None if filename not in self.mtimes: # If a module has no .py file, this will be None. self.mtimes[filename] = mtime else: if mtime is None or mtime > oldtime: # The file has been deleted or modified. self.bus.log('Restarting because %s changed.' % filename) self.thread.cancel() self.bus.log('Stopped thread %r.' % self.thread.getName()) self.bus.restart() return class ThreadManager(SimplePlugin): """Manager for HTTP request threads. If you have control over thread creation and destruction, publish to the 'acquire_thread' and 'release_thread' channels (for each thread). This will register/unregister the current thread and publish to 'start_thread' and 'stop_thread' listeners in the bus as needed. If threads are created and destroyed by code you do not control (e.g., Apache), then, at the beginning of every HTTP request, publish to 'acquire_thread' only. You should not publish to 'release_thread' in this case, since you do not know whether the thread will be re-used or not. The bus will call 'stop_thread' listeners for you when it stops. """ threads = None """A map of {thread ident: index number} pairs.""" def __init__(self, bus): self.threads = {} SimplePlugin.__init__(self, bus) self.bus.listeners.setdefault('acquire_thread', set()) self.bus.listeners.setdefault('start_thread', set()) self.bus.listeners.setdefault('release_thread', set()) self.bus.listeners.setdefault('stop_thread', set()) def acquire_thread(self): """Run 'start_thread' listeners for the current thread. If the current thread has already been seen, any 'start_thread' listeners will not be run again. """ thread_ident = get_thread_ident() if thread_ident not in self.threads: # We can't just use get_ident as the thread ID # because some platforms reuse thread ID's. i = len(self.threads) + 1 self.threads[thread_ident] = i self.bus.publish('start_thread', i) def release_thread(self): """Release the current thread and run 'stop_thread' listeners.""" thread_ident = get_thread_ident() i = self.threads.pop(thread_ident, None) if i is not None: self.bus.publish('stop_thread', i) def stop(self): """Release all threads and run all 'stop_thread' listeners.""" for thread_ident, i in self.threads.items(): self.bus.publish('stop_thread', i) self.threads.clear() graceful = stop SABnzbd-2.3.2/cherrypy/process/servers.py0000644000000000000000000003655713217005257016537 0ustar 00000000000000""" Starting in CherryPy 3.1, cherrypy.server is implemented as an :ref:`Engine Plugin`. It's an instance of :class:`cherrypy._cpserver.Server`, which is a subclass of :class:`cherrypy.process.servers.ServerAdapter`. The ``ServerAdapter`` class is designed to control other servers, as well. Multiple servers/ports ====================== If you need to start more than one HTTP server (to serve on multiple ports, or protocols, etc.), you can manually register each one and then start them all with engine.start:: s1 = ServerAdapter(cherrypy.engine, MyWSGIServer(host='0.0.0.0', port=80)) s2 = ServerAdapter(cherrypy.engine, another.HTTPServer(host='127.0.0.1', SSL=True)) s1.subscribe() s2.subscribe() cherrypy.engine.start() .. index:: SCGI FastCGI/SCGI ============ There are also Flup\ **F**\ CGIServer and Flup\ **S**\ CGIServer classes in :mod:`cherrypy.process.servers`. To start an fcgi server, for example, wrap an instance of it in a ServerAdapter:: addr = ('0.0.0.0', 4000) f = servers.FlupFCGIServer(application=cherrypy.tree, bindAddress=addr) s = servers.ServerAdapter(cherrypy.engine, httpserver=f, bind_addr=addr) s.subscribe() The :doc:`cherryd` startup script will do the above for you via its `-f` flag. Note that you need to download and install `flup `_ yourself, whether you use ``cherryd`` or not. .. _fastcgi: .. index:: FastCGI FastCGI ------- A very simple setup lets your cherry run with FastCGI. You just need the flup library, plus a running Apache server (with ``mod_fastcgi``) or lighttpd server. CherryPy code ^^^^^^^^^^^^^ hello.py:: #!/usr/bin/python import cherrypy class HelloWorld: \"""Sample request handler class.\""" @cherrypy.expose def index(self): return "Hello world!" cherrypy.tree.mount(HelloWorld()) # CherryPy autoreload must be disabled for the flup server to work cherrypy.config.update({'engine.autoreload.on':False}) Then run :doc:`/deployguide/cherryd` with the '-f' arg:: cherryd -c -d -f -i hello.py Apache ^^^^^^ At the top level in httpd.conf:: FastCgiIpcDir /tmp FastCgiServer /path/to/cherry.fcgi -idle-timeout 120 -processes 4 And inside the relevant VirtualHost section:: # FastCGI config AddHandler fastcgi-script .fcgi ScriptAliasMatch (.*$) /path/to/cherry.fcgi$1 Lighttpd ^^^^^^^^ For `Lighttpd `_ you can follow these instructions. Within ``lighttpd.conf`` make sure ``mod_fastcgi`` is active within ``server.modules``. Then, within your ``$HTTP["host"]`` directive, configure your fastcgi script like the following:: $HTTP["url"] =~ "" { fastcgi.server = ( "/" => ( "script.fcgi" => ( "bin-path" => "/path/to/your/script.fcgi", "socket" => "/tmp/script.sock", "check-local" => "disable", "disable-time" => 1, "min-procs" => 1, "max-procs" => 1, # adjust as needed ), ), ) } # end of $HTTP["url"] =~ "^/" Please see `Lighttpd FastCGI Docs `_ for an explanation of the possible configuration options. """ import os import sys import time import warnings class ServerAdapter(object): """Adapter for an HTTP server. If you need to start more than one HTTP server (to serve on multiple ports, or protocols, etc.), you can manually register each one and then start them all with bus.start:: s1 = ServerAdapter(bus, MyWSGIServer(host='0.0.0.0', port=80)) s2 = ServerAdapter(bus, another.HTTPServer(host='127.0.0.1', SSL=True)) s1.subscribe() s2.subscribe() bus.start() """ def __init__(self, bus, httpserver=None, bind_addr=None): self.bus = bus self.httpserver = httpserver self.bind_addr = bind_addr self.interrupt = None self.running = False def subscribe(self): self.bus.subscribe('start', self.start) self.bus.subscribe('stop', self.stop) def unsubscribe(self): self.bus.unsubscribe('start', self.start) self.bus.unsubscribe('stop', self.stop) def start(self): """Start the HTTP server.""" if self.bind_addr is None: on_what = 'unknown interface (dynamic?)' elif isinstance(self.bind_addr, tuple): on_what = self._get_base() else: on_what = 'socket file: %s' % self.bind_addr if self.running: self.bus.log('Already serving on %s' % on_what) return self.interrupt = None if not self.httpserver: raise ValueError('No HTTP server has been created.') if not os.environ.get('LISTEN_PID', None): # Start the httpserver in a new thread. if isinstance(self.bind_addr, tuple): wait_for_free_port(*self.bind_addr) import threading t = threading.Thread(target=self._start_http_thread) t.setName('HTTPServer ' + t.getName()) t.start() self.wait() self.running = True self.bus.log('Serving on %s' % on_what) start.priority = 75 def _get_base(self): if not self.httpserver: return '' host, port = self.bind_addr if getattr(self.httpserver, 'ssl_adapter', None): scheme = 'https' if port != 443: host += ':%s' % port else: scheme = 'http' if port != 80: host += ':%s' % port return '%s://%s' % (scheme, host) def _start_http_thread(self): """HTTP servers MUST be running in new threads, so that the main thread persists to receive KeyboardInterrupt's. If an exception is raised in the httpserver's thread then it's trapped here, and the bus (and therefore our httpserver) are shut down. """ try: self.httpserver.start() except KeyboardInterrupt: self.bus.log(' hit: shutting down HTTP server') self.interrupt = sys.exc_info()[1] self.bus.exit() except SystemExit: self.bus.log('SystemExit raised: shutting down HTTP server') self.interrupt = sys.exc_info()[1] self.bus.exit() raise except: self.interrupt = sys.exc_info()[1] self.bus.log('Error in HTTP server: shutting down', traceback=True, level=40) self.bus.exit() raise def wait(self): """Wait until the HTTP server is ready to receive requests.""" while not getattr(self.httpserver, 'ready', False): if self.interrupt: raise self.interrupt time.sleep(.1) # Wait for port to be occupied if not os.environ.get('LISTEN_PID', None): # Wait for port to be occupied if not running via socket-activation # (for socket-activation the port will be managed by systemd ) if isinstance(self.bind_addr, tuple): host, port = self.bind_addr wait_for_occupied_port(host, port) def stop(self): """Stop the HTTP server.""" if self.running: # stop() MUST block until the server is *truly* stopped. self.httpserver.stop() # Wait for the socket to be truly freed. if isinstance(self.bind_addr, tuple): wait_for_free_port(*self.bind_addr) self.running = False self.bus.log('HTTP Server %s shut down' % self.httpserver) else: self.bus.log('HTTP Server %s already shut down' % self.httpserver) stop.priority = 25 def restart(self): """Restart the HTTP server.""" self.stop() self.start() class FlupCGIServer(object): """Adapter for a flup.server.cgi.WSGIServer.""" def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs self.ready = False def start(self): """Start the CGI server.""" # We have to instantiate the server class here because its __init__ # starts a threadpool. If we do it too early, daemonize won't work. from flup.server.cgi import WSGIServer self.cgiserver = WSGIServer(*self.args, **self.kwargs) self.ready = True self.cgiserver.run() def stop(self): """Stop the HTTP server.""" self.ready = False class FlupFCGIServer(object): """Adapter for a flup.server.fcgi.WSGIServer.""" def __init__(self, *args, **kwargs): if kwargs.get('bindAddress', None) is None: import socket if not hasattr(socket, 'fromfd'): raise ValueError( 'Dynamic FCGI server not available on this platform. ' 'You must use a static or external one by providing a ' 'legal bindAddress.') self.args = args self.kwargs = kwargs self.ready = False def start(self): """Start the FCGI server.""" # We have to instantiate the server class here because its __init__ # starts a threadpool. If we do it too early, daemonize won't work. from flup.server.fcgi import WSGIServer self.fcgiserver = WSGIServer(*self.args, **self.kwargs) # TODO: report this bug upstream to flup. # If we don't set _oldSIGs on Windows, we get: # File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py", # line 108, in run # self._restoreSignalHandlers() # File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py", # line 156, in _restoreSignalHandlers # for signum,handler in self._oldSIGs: # AttributeError: 'WSGIServer' object has no attribute '_oldSIGs' self.fcgiserver._installSignalHandlers = lambda: None self.fcgiserver._oldSIGs = [] self.ready = True self.fcgiserver.run() def stop(self): """Stop the HTTP server.""" # Forcibly stop the fcgi server main event loop. self.fcgiserver._keepGoing = False # Force all worker threads to die off. self.fcgiserver._threadPool.maxSpare = ( self.fcgiserver._threadPool._idleCount) self.ready = False class FlupSCGIServer(object): """Adapter for a flup.server.scgi.WSGIServer.""" def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs self.ready = False def start(self): """Start the SCGI server.""" # We have to instantiate the server class here because its __init__ # starts a threadpool. If we do it too early, daemonize won't work. from flup.server.scgi import WSGIServer self.scgiserver = WSGIServer(*self.args, **self.kwargs) # TODO: report this bug upstream to flup. # If we don't set _oldSIGs on Windows, we get: # File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py", # line 108, in run # self._restoreSignalHandlers() # File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py", # line 156, in _restoreSignalHandlers # for signum,handler in self._oldSIGs: # AttributeError: 'WSGIServer' object has no attribute '_oldSIGs' self.scgiserver._installSignalHandlers = lambda: None self.scgiserver._oldSIGs = [] self.ready = True self.scgiserver.run() def stop(self): """Stop the HTTP server.""" self.ready = False # Forcibly stop the scgi server main event loop. self.scgiserver._keepGoing = False # Force all worker threads to die off. self.scgiserver._threadPool.maxSpare = 0 def client_host(server_host): """Return the host on which a client can connect to the given listener.""" if server_host == '0.0.0.0': # 0.0.0.0 is INADDR_ANY, which should answer on localhost. return '127.0.0.1' if server_host in ('::', '::0', '::0.0.0.0'): # :: is IN6ADDR_ANY, which should answer on localhost. # ::0 and ::0.0.0.0 are non-canonical but common # ways to write IN6ADDR_ANY. return '::1' return server_host def check_port(host, port, timeout=1.0): """Raise an error if the given port is not free on the given host.""" if not host: raise ValueError("Host values of '' or None are not allowed.") host = client_host(host) port = int(port) import socket # AF_INET or AF_INET6 socket # Get the correct address family for our host (allows IPv6 addresses) try: info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM) except socket.gaierror: if ':' in host: info = [( socket.AF_INET6, socket.SOCK_STREAM, 0, '', (host, port, 0, 0) )] else: info = [(socket.AF_INET, socket.SOCK_STREAM, 0, '', (host, port))] for res in info: af, socktype, proto, canonname, sa = res s = None try: s = socket.socket(af, socktype, proto) # See http://groups.google.com/group/cherrypy-users/ # browse_frm/thread/bbfe5eb39c904fe0 s.settimeout(timeout) s.connect((host, port)) s.close() except socket.error: if s: s.close() else: raise IOError('Port %s is in use on %s; perhaps the previous ' 'httpserver did not shut down properly.' % (repr(port), repr(host))) # Feel free to increase these defaults on slow systems: free_port_timeout = 0.1 occupied_port_timeout = 1.0 def wait_for_free_port(host, port, timeout=None): """Wait for the specified port to become free (drop requests).""" if not host: raise ValueError("Host values of '' or None are not allowed.") if timeout is None: timeout = free_port_timeout for trial in range(50): try: # we are expecting a free port, so reduce the timeout check_port(host, port, timeout=timeout) except IOError: # Give the old server thread time to free the port. time.sleep(timeout) else: return raise IOError('Port %r not free on %r' % (port, host)) def wait_for_occupied_port(host, port, timeout=None): """Wait for the specified port to become active (receive requests).""" if not host: raise ValueError("Host values of '' or None are not allowed.") if timeout is None: timeout = occupied_port_timeout for trial in range(50): try: check_port(host, port, timeout=timeout) except IOError: # port is occupied return else: time.sleep(timeout) if host == client_host(host): raise IOError('Port %r not bound on %r' % (port, host)) # On systems where a loopback interface is not available and the # server is bound to all interfaces, it's difficult to determine # whether the server is in fact occupying the port. In this case, # just issue a warning and move on. See issue #1100. msg = 'Unable to verify that the server is bound on %r' % port warnings.warn(msg) SABnzbd-2.3.2/cherrypy/process/win32.py0000644000000000000000000001321413217005257015771 0ustar 00000000000000"""Windows service. Requires pywin32.""" import os import win32api import win32con import win32event import win32service import win32serviceutil from cherrypy.process import wspbus, plugins class ConsoleCtrlHandler(plugins.SimplePlugin): """A WSPBus plugin for handling Win32 console events (like Ctrl-C).""" def __init__(self, bus): self.is_set = False plugins.SimplePlugin.__init__(self, bus) def start(self): if self.is_set: self.bus.log('Handler for console events already set.', level=40) return result = win32api.SetConsoleCtrlHandler(self.handle, 1) if result == 0: self.bus.log('Could not SetConsoleCtrlHandler (error %r)' % win32api.GetLastError(), level=40) else: self.bus.log('Set handler for console events.', level=40) self.is_set = True def stop(self): if not self.is_set: self.bus.log('Handler for console events already off.', level=40) return try: result = win32api.SetConsoleCtrlHandler(self.handle, 0) except ValueError: # "ValueError: The object has not been registered" result = 1 if result == 0: self.bus.log('Could not remove SetConsoleCtrlHandler (error %r)' % win32api.GetLastError(), level=40) else: self.bus.log('Removed handler for console events.', level=40) self.is_set = False def handle(self, event): """Handle console control events (like Ctrl-C).""" if event in (win32con.CTRL_C_EVENT, win32con.CTRL_LOGOFF_EVENT, win32con.CTRL_BREAK_EVENT, win32con.CTRL_SHUTDOWN_EVENT, win32con.CTRL_CLOSE_EVENT): self.bus.log('Console event %s: shutting down bus' % event) # Remove self immediately so repeated Ctrl-C doesn't re-call it. try: self.stop() except ValueError: pass self.bus.exit() # 'First to return True stops the calls' return 1 return 0 class Win32Bus(wspbus.Bus): """A Web Site Process Bus implementation for Win32. Instead of time.sleep, this bus blocks using native win32event objects. """ def __init__(self): self.events = {} wspbus.Bus.__init__(self) def _get_state_event(self, state): """Return a win32event for the given state (creating it if needed).""" try: return self.events[state] except KeyError: event = win32event.CreateEvent(None, 0, 0, 'WSPBus %s Event (pid=%r)' % (state.name, os.getpid())) self.events[state] = event return event def _get_state(self): return self._state def _set_state(self, value): self._state = value event = self._get_state_event(value) win32event.PulseEvent(event) state = property(_get_state, _set_state) def wait(self, state, interval=0.1, channel=None): """Wait for the given state(s), KeyboardInterrupt or SystemExit. Since this class uses native win32event objects, the interval argument is ignored. """ if isinstance(state, (tuple, list)): # Don't wait for an event that beat us to the punch ;) if self.state not in state: events = tuple([self._get_state_event(s) for s in state]) win32event.WaitForMultipleObjects( events, 0, win32event.INFINITE) else: # Don't wait for an event that beat us to the punch ;) if self.state != state: event = self._get_state_event(state) win32event.WaitForSingleObject(event, win32event.INFINITE) class _ControlCodes(dict): """Control codes used to "signal" a service via ControlService. User-defined control codes are in the range 128-255. We generally use the standard Python value for the Linux signal and add 128. Example: >>> signal.SIGUSR1 10 control_codes['graceful'] = 128 + 10 """ def key_for(self, obj): """For the given value, return its corresponding key.""" for key, val in self.items(): if val is obj: return key raise ValueError('The given object could not be found: %r' % obj) control_codes = _ControlCodes({'graceful': 138}) def signal_child(service, command): if command == 'stop': win32serviceutil.StopService(service) elif command == 'restart': win32serviceutil.RestartService(service) else: win32serviceutil.ControlService(service, control_codes[command]) class PyWebService(win32serviceutil.ServiceFramework): """Python Web Service.""" _svc_name_ = 'Python Web Service' _svc_display_name_ = 'Python Web Service' _svc_deps_ = None # sequence of service names on which this depends _exe_name_ = 'pywebsvc' _exe_args_ = None # Default to no arguments # Only exists on Windows 2000 or later, ignored on windows NT _svc_description_ = 'Python Web Service' def SvcDoRun(self): from cherrypy import process process.bus.start() process.bus.block() def SvcStop(self): from cherrypy import process self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) process.bus.exit() def SvcOther(self, control): process.bus.publish(control_codes.key_for(control)) if __name__ == '__main__': win32serviceutil.HandleCommandLine(PyWebService) SABnzbd-2.3.2/cherrypy/process/wspbus.py0000644000000000000000000004472413217005257016364 0ustar 00000000000000"""An implementation of the Web Site Process Bus. This module is completely standalone, depending only on the stdlib. Web Site Process Bus -------------------- A Bus object is used to contain and manage site-wide behavior: daemonization, HTTP server start/stop, process reload, signal handling, drop privileges, PID file management, logging for all of these, and many more. In addition, a Bus object provides a place for each web framework to register code that runs in response to site-wide events (like process start and stop), or which controls or otherwise interacts with the site-wide components mentioned above. For example, a framework which uses file-based templates would add known template filenames to an autoreload component. Ideally, a Bus object will be flexible enough to be useful in a variety of invocation scenarios: 1. The deployer starts a site from the command line via a framework-neutral deployment script; applications from multiple frameworks are mixed in a single site. Command-line arguments and configuration files are used to define site-wide components such as the HTTP server, WSGI component graph, autoreload behavior, signal handling, etc. 2. The deployer starts a site via some other process, such as Apache; applications from multiple frameworks are mixed in a single site. Autoreload and signal handling (from Python at least) are disabled. 3. The deployer starts a site via a framework-specific mechanism; for example, when running tests, exploring tutorials, or deploying single applications from a single framework. The framework controls which site-wide components are enabled as it sees fit. The Bus object in this package uses topic-based publish-subscribe messaging to accomplish all this. A few topic channels are built in ('start', 'stop', 'exit', 'graceful', 'log', and 'main'). Frameworks and site containers are free to define their own. If a message is sent to a channel that has not been defined or has no listeners, there is no effect. In general, there should only ever be a single Bus object per process. Frameworks and site containers share a single Bus object by publishing messages and subscribing listeners. The Bus object works as a finite state machine which models the current state of the process. Bus methods move it from one state to another; those methods then publish to subscribed listeners on the channel for the new state.:: O | V STOPPING --> STOPPED --> EXITING -> X A A | | \___ | | \ | | V V STARTED <-- STARTING """ import atexit import ctypes import operator import os import subprocess import sys import threading import time import traceback as _traceback import warnings import six from cherrypy._cpcompat import _args_from_interpreter_flags # Here I save the value of os.getcwd(), which, if I am imported early enough, # will be the directory from which the startup script was run. This is needed # by _do_execv(), to change back to the original directory before execv()ing a # new process. This is a defense against the application having changed the # current working directory (which could make sys.executable "not found" if # sys.executable is a relative-path, and/or cause other problems). _startup_cwd = os.getcwd() class ChannelFailures(Exception): """Exception raised when errors occur in a listener during Bus.publish(). """ delimiter = '\n' def __init__(self, *args, **kwargs): super(Exception, self).__init__(*args, **kwargs) self._exceptions = list() def handle_exception(self): """Append the current exception to self.""" self._exceptions.append(sys.exc_info()[1]) def get_instances(self): """Return a list of seen exception instances.""" return self._exceptions[:] def __str__(self): exception_strings = map(repr, self.get_instances()) return self.delimiter.join(exception_strings) __repr__ = __str__ def __bool__(self): return bool(self._exceptions) __nonzero__ = __bool__ # Use a flag to indicate the state of the bus. class _StateEnum(object): class State(object): name = None def __repr__(self): return 'states.%s' % self.name def __setattr__(self, key, value): if isinstance(value, self.State): value.name = key object.__setattr__(self, key, value) states = _StateEnum() states.STOPPED = states.State() states.STARTING = states.State() states.STARTED = states.State() states.STOPPING = states.State() states.EXITING = states.State() try: import fcntl except ImportError: max_files = 0 else: try: max_files = os.sysconf('SC_OPEN_MAX') except AttributeError: max_files = 1024 class Bus(object): """Process state-machine and messenger for HTTP site deployment. All listeners for a given channel are guaranteed to be called even if others at the same channel fail. Each failure is logged, but execution proceeds on to the next listener. The only way to stop all processing from inside a listener is to raise SystemExit and stop the whole server. """ states = states state = states.STOPPED execv = False max_cloexec_files = max_files def __init__(self): self.execv = False self.state = states.STOPPED channels = 'start', 'stop', 'exit', 'graceful', 'log', 'main' self.listeners = dict( (channel, set()) for channel in channels ) self._priorities = {} def subscribe(self, channel, callback, priority=None): """Add the given callback at the given channel (if not present).""" ch_listeners = self.listeners.setdefault(channel, set()) ch_listeners.add(callback) if priority is None: priority = getattr(callback, 'priority', 50) self._priorities[(channel, callback)] = priority def unsubscribe(self, channel, callback): """Discard the given callback (if present).""" listeners = self.listeners.get(channel) if listeners and callback in listeners: listeners.discard(callback) del self._priorities[(channel, callback)] def publish(self, channel, *args, **kwargs): """Return output of all subscribers for the given channel.""" if channel not in self.listeners: return [] exc = ChannelFailures() output = [] raw_items = ( (self._priorities[(channel, listener)], listener) for listener in self.listeners[channel] ) items = sorted(raw_items, key=operator.itemgetter(0)) for priority, listener in items: try: output.append(listener(*args, **kwargs)) except KeyboardInterrupt: raise except SystemExit: e = sys.exc_info()[1] # If we have previous errors ensure the exit code is non-zero if exc and e.code == 0: e.code = 1 raise except: exc.handle_exception() if channel == 'log': # Assume any further messages to 'log' will fail. pass else: self.log('Error in %r listener %r' % (channel, listener), level=40, traceback=True) if exc: raise exc return output def _clean_exit(self): """An atexit handler which asserts the Bus is not running.""" if self.state != states.EXITING: warnings.warn( 'The main thread is exiting, but the Bus is in the %r state; ' 'shutting it down automatically now. You must either call ' 'bus.block() after start(), or call bus.exit() before the ' 'main thread exits.' % self.state, RuntimeWarning) self.exit() def start(self): """Start all services.""" atexit.register(self._clean_exit) self.state = states.STARTING self.log('Bus STARTING') try: self.publish('start') self.state = states.STARTED self.log('Bus STARTED') except (KeyboardInterrupt, SystemExit): raise except: self.log('Shutting down due to error in start listener:', level=40, traceback=True) e_info = sys.exc_info()[1] try: self.exit() except: # Any stop/exit errors will be logged inside publish(). pass # Re-raise the original error raise e_info def exit(self): """Stop all services and prepare to exit the process.""" exitstate = self.state try: self.stop() self.state = states.EXITING self.log('Bus EXITING') self.publish('exit') # This isn't strictly necessary, but it's better than seeing # "Waiting for child threads to terminate..." and then nothing. self.log('Bus EXITED') except: # This method is often called asynchronously (whether thread, # signal handler, console handler, or atexit handler), so we # can't just let exceptions propagate out unhandled. # Assume it's been logged and just die. os._exit(70) # EX_SOFTWARE if exitstate == states.STARTING: # exit() was called before start() finished, possibly due to # Ctrl-C because a start listener got stuck. In this case, # we could get stuck in a loop where Ctrl-C never exits the # process, so we just call os.exit here. os._exit(70) # EX_SOFTWARE def restart(self): """Restart the process (may close connections). This method does not restart the process from the calling thread; instead, it stops the bus and asks the main thread to call execv. """ self.execv = True self.exit() def graceful(self): """Advise all services to reload.""" self.log('Bus graceful') self.publish('graceful') def block(self, interval=0.1): """Wait for the EXITING state, KeyboardInterrupt or SystemExit. This function is intended to be called only by the main thread. After waiting for the EXITING state, it also waits for all threads to terminate, and then calls os.execv if self.execv is True. This design allows another thread to call bus.restart, yet have the main thread perform the actual execv call (required on some platforms). """ try: self.wait(states.EXITING, interval=interval, channel='main') except (KeyboardInterrupt, IOError): # The time.sleep call might raise # "IOError: [Errno 4] Interrupted function call" on KBInt. self.log('Keyboard Interrupt: shutting down bus') self.exit() except SystemExit: self.log('SystemExit raised: shutting down bus') self.exit() raise # Waiting for ALL child threads to finish is necessary on OS X. # See https://github.com/cherrypy/cherrypy/issues/581. # It's also good to let them all shut down before allowing # the main thread to call atexit handlers. # See https://github.com/cherrypy/cherrypy/issues/751. self.log('Waiting for child threads to terminate...') for t in threading.enumerate(): # Validate the we're not trying to join the MainThread # that will cause a deadlock and the case exist when # implemented as a windows service and in any other case # that another thread executes cherrypy.engine.exit() if ( t != threading.currentThread() and t.isAlive() and not isinstance(t, threading._MainThread) ): # Note that any dummy (external) threads are always daemonic. if hasattr(threading.Thread, 'daemon'): # Python 2.6+ d = t.daemon else: d = t.isDaemon() if not d: self.log('Waiting for thread %s.' % t.getName()) t.join() if self.execv: self._do_execv() def wait(self, state, interval=0.1, channel=None): """Poll for the given state(s) at intervals; publish to channel.""" if isinstance(state, (tuple, list)): states = state else: states = [state] def _wait(): while self.state not in states: time.sleep(interval) self.publish(channel) # From http://psyco.sourceforge.net/psycoguide/bugs.html: # "The compiled machine code does not include the regular polling # done by Python, meaning that a KeyboardInterrupt will not be # detected before execution comes back to the regular Python # interpreter. Your program cannot be interrupted if caught # into an infinite Psyco-compiled loop." try: sys.modules['psyco'].cannotcompile(_wait) except (KeyError, AttributeError): pass _wait() def _do_execv(self): """Re-execute the current process. This must be called from the main thread, because certain platforms (OS X) don't allow execv to be called in a child thread very well. """ try: args = self._get_true_argv() except NotImplementedError: """It's probably win32""" # For the SABnzbd.exe binary we don't want interpreter flags # https://github.com/cherrypy/cherrypy/issues/1526 if getattr(sys, 'frozen', False): args = [sys.executable] + sys.argv else: args = [sys.executable] + _args_from_interpreter_flags() + sys.argv self.log('Re-spawning %s' % ' '.join(args)) self._extend_pythonpath(os.environ) if sys.platform[:4] == 'java': from _systemrestart import SystemRestart raise SystemRestart else: if sys.platform == 'win32': args = ['"%s"' % arg for arg in args] os.chdir(_startup_cwd) if self.max_cloexec_files: self._set_cloexec() os.execv(sys.executable, args) @staticmethod def _get_true_argv(): """Retrieves all real arguments of the python interpreter ...even those not listed in ``sys.argv`` :seealso: http://stackoverflow.com/a/28338254/595220 :seealso: http://stackoverflow.com/a/6683222/595220 :seealso: http://stackoverflow.com/a/28414807/595220 """ try: char_p = ctypes.c_char_p if six.PY2 else ctypes.c_wchar_p argv = ctypes.POINTER(char_p)() argc = ctypes.c_int() ctypes.pythonapi.Py_GetArgcArgv(ctypes.byref(argc), ctypes.byref(argv)) except AttributeError: """It looks Py_GetArgcArgv is completely absent in MS Windows :seealso: https://github.com/cherrypy/cherrypy/issues/1506 :ref: https://chromium.googlesource.com/infra/infra/+/69eb0279c12bcede5937ce9298020dd4581e38dd%5E!/ """ raise NotImplementedError else: return argv[:argc.value] @staticmethod def _extend_pythonpath(env): """ If sys.path[0] is an empty string, the interpreter was likely invoked with -m and the effective path is about to change on re-exec. Add the current directory to $PYTHONPATH to ensure that the new process sees the same path. This issue cannot be addressed in the general case because Python cannot reliably reconstruct the original command line (http://bugs.python.org/issue14208). (This idea filched from tornado.autoreload) """ path_prefix = '.' + os.pathsep existing_path = env.get('PYTHONPATH', '') needs_patch = ( sys.path[0] == '' and not existing_path.startswith(path_prefix) ) if needs_patch: env['PYTHONPATH'] = path_prefix + existing_path def _set_cloexec(self): """Set the CLOEXEC flag on all open files (except stdin/out/err). If self.max_cloexec_files is an integer (the default), then on platforms which support it, it represents the max open files setting for the operating system. This function will be called just before the process is restarted via os.execv() to prevent open files from persisting into the new process. Set self.max_cloexec_files to 0 to disable this behavior. """ for fd in range(3, self.max_cloexec_files): # skip stdin/out/err try: flags = fcntl.fcntl(fd, fcntl.F_GETFD) except IOError: continue fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) def stop(self): """Stop all services.""" self.state = states.STOPPING self.log('Bus STOPPING') self.publish('stop') self.state = states.STOPPED self.log('Bus STOPPED') def start_with_callback(self, func, args=None, kwargs=None): """Start 'func' in a new thread T, then start self (and return T).""" if args is None: args = () if kwargs is None: kwargs = {} args = (func,) + args def _callback(func, *a, **kw): self.wait(states.STARTED) func(*a, **kw) t = threading.Thread(target=_callback, args=args, kwargs=kwargs) t.setName('Bus Callback ' + t.getName()) t.start() self.start() return t def log(self, msg='', level=20, traceback=False): """Log the given message. Append the last traceback if requested.""" if traceback: # Work-around for bug in Python's traceback implementation # which crashes when the error message contains %1, %2 etc. errors = sys.exc_info() if '%' in errors[1].message: errors[1].message = errors[1].message.replace('%', '#') errors[1].args = [item.replace('%', '#') for item in errors[1].args] msg += "\n" + "".join(_traceback.format_exception(*errors)) self.publish('log', msg, level) bus = Bus() SABnzbd-2.3.2/cherrypy/process/__init__.py0000644000000000000000000000105013217005257016561 0ustar 00000000000000"""Site container for an HTTP server. A Web Site Process Bus object is used to connect applications, servers, and frameworks with site-wide services such as daemonization, process reload, signal handling, drop privileges, PID file management, logging for all of these, and many more. The 'plugins' module defines a few abstract and concrete services for use with the bus. Some use tool-specific channels; see the documentation for each class. """ from cherrypy.process.wspbus import bus # noqa from cherrypy.process import plugins, servers # noqa SABnzbd-2.3.2/cherrypy/wsgiserver/ssl_builtin.py0000644000000000000000000001124213217005257020077 0ustar 00000000000000"""A library for integrating Python's builtin ``ssl`` library with CherryPy. The ssl module must be importable for SSL functionality. To use this module, set ``CherryPyWSGIServer.ssl_adapter`` to an instance of ``BuiltinSSLAdapter``. """ try: import ssl except ImportError: ssl = None try: from _pyio import DEFAULT_BUFFER_SIZE except ImportError: try: from io import DEFAULT_BUFFER_SIZE except ImportError: DEFAULT_BUFFER_SIZE = -1 import sys from cherrypy import wsgiserver class BuiltinSSLAdapter(wsgiserver.SSLAdapter): """A wrapper for integrating Python's builtin ssl module with CherryPy.""" certificate = None """The filename of the server SSL certificate.""" private_key = None """The filename of the server's private key file.""" certificate_chain = None """The filename of the certificate chain file.""" """The ssl.SSLContext that will be used to wrap sockets where available (on Python > 2.7.9 / 3.3) """ context = None def __init__(self, certificate, private_key, certificate_chain=None): if ssl is None: raise ImportError('You must install the ssl module to use HTTPS.') self.certificate = certificate self.private_key = private_key self.certificate_chain = certificate_chain if hasattr(ssl, 'create_default_context'): self.context = ssl.create_default_context( purpose=ssl.Purpose.CLIENT_AUTH, cafile=certificate_chain ) self.context.load_cert_chain(certificate, private_key) def bind(self, sock): """Wrap and return the given socket.""" return sock def wrap(self, sock): """Wrap and return the given socket, plus WSGI environ entries.""" try: if self.context is not None: s = self.context.wrap_socket(sock,do_handshake_on_connect=True, server_side=True) else: s = ssl.wrap_socket(sock, do_handshake_on_connect=True, server_side=True, certfile=self.certificate, keyfile=self.private_key, ssl_version=ssl.PROTOCOL_SSLv23, ca_certs=self.certificate_chain) except ssl.SSLError: e = sys.exc_info()[1] if e.errno == ssl.SSL_ERROR_EOF: # This is almost certainly due to the cherrypy engine # 'pinging' the socket to assert it's connectable; # the 'ping' isn't SSL. return None, {} elif e.errno == ssl.SSL_ERROR_SSL: if 'http request' in e.args[1]: # The client is speaking HTTP to an HTTPS server. raise wsgiserver.NoSSLError # Check if it's one of the known errors # Errors that are caught by PyOpenSSL, but thrown by built-in ssl _block_errors = ('unknown protocol', 'unknown ca', 'unknown_ca', 'unknown error', 'https proxy request', 'inappropriate fallback', 'wrong version number', 'no shared cipher', 'certificate unknown', 'ccs received early') for error_text in _block_errors: if error_text in e.args[1].lower(): # Accepted error, let's pass return None, {} elif 'handshake operation timed out' in e.args[0]: # This error is thrown by builtin SSL after a timeout # when client is speaking HTTP to an HTTPS server. # The connection can safely be dropped. return None, {} raise except: # Temporary fix for https://github.com/cherrypy/cherrypy/issues/1618 e = sys.exc_info()[1] if e.args == (0, 'Error'): return None, {} raise return s, self.get_environ(s) # TODO: fill this out more with mod ssl env def get_environ(self, sock): """Create WSGI environ entries to be merged into each request.""" cipher = sock.cipher() ssl_environ = { 'wsgi.url_scheme': 'https', 'HTTPS': 'on', 'SSL_PROTOCOL': cipher[1], 'SSL_CIPHER': cipher[0] # SSL_VERSION_INTERFACE string The mod_ssl program version # SSL_VERSION_LIBRARY string The OpenSSL program version } return ssl_environ def makefile(self, sock, mode='r', bufsize=DEFAULT_BUFFER_SIZE): return wsgiserver.CP_makefile(sock, mode, bufsize) SABnzbd-2.3.2/cherrypy/wsgiserver/ssl_pyopenssl.py0000644000000000000000000002200513217005257020464 0ustar 00000000000000"""A library for integrating pyOpenSSL with CherryPy. The OpenSSL module must be importable for SSL functionality. You can obtain it from `here `_. To use this module, set CherryPyWSGIServer.ssl_adapter to an instance of SSLAdapter. There are two ways to use SSL: Method One ---------- * ``ssl_adapter.context``: an instance of SSL.Context. If this is not None, it is assumed to be an SSL.Context instance, and will be passed to SSL.Connection on bind(). The developer is responsible for forming a valid Context object. This approach is to be preferred for more flexibility, e.g. if the cert and key are streams instead of files, or need decryption, or SSL.SSLv3_METHOD is desired instead of the default SSL.SSLv23_METHOD, etc. Consult the pyOpenSSL documentation for complete options. Method Two (shortcut) --------------------- * ``ssl_adapter.certificate``: the filename of the server SSL certificate. * ``ssl_adapter.private_key``: the filename of the server's private key file. Both are None by default. If ssl_adapter.context is None, but .private_key and .certificate are both given and valid, they will be read, and the context will be automatically created from them. """ import socket import threading import time from cherrypy import wsgiserver try: from OpenSSL import SSL from OpenSSL import crypto except ImportError: SSL = None class SSL_fileobject(wsgiserver.CP_makefile): """SSL file object attached to a socket object.""" ssl_timeout = 3 ssl_retry = .01 def _safe_call(self, is_reader, call, *args, **kwargs): """Wrap the given call with SSL error-trapping. is_reader: if False EOF errors will be raised. If True, EOF errors will return "" (to emulate normal sockets). """ start = time.time() while True: try: return call(*args, **kwargs) except SSL.WantReadError: # Sleep and try again. This is dangerous, because it means # the rest of the stack has no way of differentiating # between a "new handshake" error and "client dropped". # Note this isn't an endless loop: there's a timeout below. time.sleep(self.ssl_retry) except SSL.WantWriteError: time.sleep(self.ssl_retry) except SSL.SysCallError as e: if is_reader and e.args == (-1, 'Unexpected EOF'): return '' errnum = e.args[0] if is_reader and errnum in wsgiserver.socket_errors_to_ignore: return '' raise socket.error(errnum) except SSL.Error as e: if is_reader and e.args == (-1, 'Unexpected EOF'): return '' thirdarg = None try: thirdarg = e.args[0][0][2] except IndexError: pass if thirdarg == 'http request': # The client is talking HTTP to an HTTPS server. raise wsgiserver.NoSSLError() raise wsgiserver.FatalSSLAlert(*e.args) except: raise if time.time() - start > self.ssl_timeout: raise socket.timeout('timed out') def recv(self, size): return self._safe_call(True, super(SSL_fileobject, self).recv, size) def sendall(self, *args, **kwargs): return self._safe_call(False, super(SSL_fileobject, self).sendall, *args, **kwargs) def send(self, *args, **kwargs): return self._safe_call(False, super(SSL_fileobject, self).send, *args, **kwargs) class SSLConnection: """A thread-safe wrapper for an SSL.Connection. ``*args``: the arguments to create the wrapped ``SSL.Connection(*args)``. """ def __init__(self, *args): self._ssl_conn = SSL.Connection(*args) self._lock = threading.RLock() for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read', 'renegotiate', 'bind', 'listen', 'connect', 'accept', 'setblocking', 'fileno', 'close', 'get_cipher_list', 'getpeername', 'getsockname', 'getsockopt', 'setsockopt', 'makefile', 'get_app_data', 'set_app_data', 'state_string', 'sock_shutdown', 'get_peer_certificate', 'want_read', 'want_write', 'set_connect_state', 'set_accept_state', 'connect_ex', 'sendall', 'settimeout', 'gettimeout'): exec("""def %s(self, *args): self._lock.acquire() try: return self._ssl_conn.%s(*args) finally: self._lock.release() """ % (f, f)) def shutdown(self, *args): self._lock.acquire() try: # pyOpenSSL.socket.shutdown takes no args return self._ssl_conn.shutdown() finally: self._lock.release() class pyOpenSSLAdapter(wsgiserver.SSLAdapter): """A wrapper for integrating pyOpenSSL with CherryPy.""" context = None """An instance of SSL.Context.""" certificate = None """The filename of the server SSL certificate.""" private_key = None """The filename of the server's private key file.""" certificate_chain = None """Optional. The filename of CA's intermediate certificate bundle. This is needed for cheaper "chained root" SSL certificates, and should be left as None if not required.""" def __init__(self, certificate, private_key, certificate_chain=None): if SSL is None: raise ImportError('You must install pyOpenSSL to use HTTPS.') self.context = None self.certificate = certificate self.private_key = private_key self.certificate_chain = certificate_chain self._environ = None def bind(self, sock): """Wrap and return the given socket.""" if self.context is None: self.context = self.get_context() conn = SSLConnection(self.context, sock) self._environ = self.get_environ() return conn def wrap(self, sock): """Wrap and return the given socket, plus WSGI environ entries.""" return sock, self._environ.copy() def get_context(self): """Return an SSL.Context from self attributes.""" # See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442473 c = SSL.Context(SSL.SSLv23_METHOD) c.use_privatekey_file(self.private_key) if self.certificate_chain: c.load_verify_locations(self.certificate_chain) c.use_certificate_file(self.certificate) return c def get_environ(self): """Return WSGI environ entries to be merged into each request.""" ssl_environ = { 'HTTPS': 'on', # pyOpenSSL doesn't provide access to any of these AFAICT # 'SSL_PROTOCOL': 'SSLv2', # SSL_CIPHER string The cipher specification name # SSL_VERSION_INTERFACE string The mod_ssl program version # SSL_VERSION_LIBRARY string The OpenSSL program version } if self.certificate: # Server certificate attributes cert = open(self.certificate, 'rb').read() cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert) ssl_environ.update({ 'SSL_SERVER_M_VERSION': cert.get_version(), 'SSL_SERVER_M_SERIAL': cert.get_serial_number(), # 'SSL_SERVER_V_START': # Validity of server's certificate (start time), # 'SSL_SERVER_V_END': # Validity of server's certificate (end time), }) for prefix, dn in [('I', cert.get_issuer()), ('S', cert.get_subject())]: # X509Name objects don't seem to have a way to get the # complete DN string. Use str() and slice it instead, # because str(dn) == "" dnstr = str(dn)[18:-2] wsgikey = 'SSL_SERVER_%s_DN' % prefix ssl_environ[wsgikey] = dnstr # The DN should be of the form: /k1=v1/k2=v2, but we must allow # for any value to contain slashes itself (in a URL). while dnstr: pos = dnstr.rfind('=') dnstr, value = dnstr[:pos], dnstr[pos + 1:] pos = dnstr.rfind('/') dnstr, key = dnstr[:pos], dnstr[pos + 1:] if key and value: wsgikey = 'SSL_SERVER_%s_DN_%s' % (prefix, key) ssl_environ[wsgikey] = value return ssl_environ def makefile(self, sock, mode='r', bufsize=-1): if SSL and isinstance(sock, SSL.ConnectionType): timeout = sock.gettimeout() f = SSL_fileobject(sock, mode, bufsize) f.ssl_timeout = timeout return f else: return wsgiserver.CP_fileobject(sock, mode, bufsize) SABnzbd-2.3.2/cherrypy/wsgiserver/__init__.py0000644000000000000000000026534513217005257017326 0ustar 00000000000000"""A high-speed, production ready, thread pooled, generic HTTP server. Simplest example on how to use this module directly (without using CherryPy's application machinery):: from cherrypy import wsgiserver def my_crazy_app(environ, start_response): status = '200 OK' response_headers = [('Content-type','text/plain')] start_response(status, response_headers) return ['Hello world!'] server = wsgiserver.CherryPyWSGIServer( ('0.0.0.0', 8070), my_crazy_app, server_name='www.cherrypy.example') server.start() The CherryPy WSGI server can serve as many WSGI applications as you want in one instance by using a WSGIPathInfoDispatcher:: d = WSGIPathInfoDispatcher({'/': my_crazy_app, '/blog': my_blog_app}) server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 80), d) Want SSL support? Just set server.ssl_adapter to an SSLAdapter instance. This won't call the CherryPy engine (application side) at all, only the HTTP server, which is independent from the rest of CherryPy. Don't let the name "CherryPyWSGIServer" throw you; the name merely reflects its origin, not its coupling. For those of you wanting to understand internals of this module, here's the basic call flow. The server's listening thread runs a very tight loop, sticking incoming connections onto a Queue:: server = CherryPyWSGIServer(...) server.start() while True: tick() # This blocks until a request comes in: child = socket.accept() conn = HTTPConnection(child, ...) server.requests.put(conn) Worker threads are kept in a pool and poll the Queue, popping off and then handling each connection in turn. Each connection can consist of an arbitrary number of requests and their responses, so we run a nested loop:: while True: conn = server.requests.get() conn.communicate() -> while True: req = HTTPRequest(...) req.parse_request() -> # Read the Request-Line, e.g. "GET /page HTTP/1.1" req.rfile.readline() read_headers(req.rfile, req.inheaders) req.respond() -> response = app(...) try: for chunk in response: if chunk: req.write(chunk) finally: if hasattr(response, "close"): response.close() if req.close_connection: return """ import os try: import queue except: import Queue as queue import re import email.utils import socket import sys import threading import time import traceback as traceback_ try: from urllib.parse import unquote_to_bytes, urlparse except ImportError: from urlparse import unquote as unquote_to_bytes from urlparse import urlparse import errno import logging import six from six.moves import filter try: # prefer slower Python-based io module import _pyio as io except ImportError: # Python 2.6 import io try: import pkg_resources except ImportError: pass __all__ = ['HTTPRequest', 'HTTPConnection', 'HTTPServer', 'SizeCheckWrapper', 'KnownLengthRFile', 'ChunkedRFile', 'CP_makefile', 'MaxSizeExceeded', 'NoSSLError', 'FatalSSLAlert', 'WorkerThread', 'ThreadPool', 'SSLAdapter', 'CherryPyWSGIServer', 'Gateway', 'WSGIGateway', 'WSGIGateway_10', 'WSGIGateway_u0', 'WSGIPathInfoDispatcher', 'get_ssl_adapter_class', 'socket_errors_to_ignore'] if 'win' in sys.platform and hasattr(socket, 'AF_INET6'): if not hasattr(socket, 'IPPROTO_IPV6'): socket.IPPROTO_IPV6 = 41 if not hasattr(socket, 'IPV6_V6ONLY'): socket.IPV6_V6ONLY = 27 DEFAULT_BUFFER_SIZE = io.DEFAULT_BUFFER_SIZE try: cp_version = pkg_resources.require('cherrypy')[0].version except Exception: cp_version = 'unknown' if six.PY3: def ntob(n, encoding='ISO-8859-1'): """Return the given native string as a byte string in the given encoding. """ # In Python 3, the native string type is unicode return n.encode(encoding) def bton(b, encoding='ISO-8859-1'): return b.decode(encoding) else: def ntob(n, encoding='ISO-8859-1'): """Return the given native string as a byte string in the given encoding. """ # In Python 2, the native string type is bytes. Assume it's already # in the given encoding, which for ISO-8859-1 is almost always what # was intended. return n def bton(b, encoding='ISO-8859-1'): return b LF = ntob('\n') CRLF = ntob('\r\n') TAB = ntob('\t') SPACE = ntob(' ') COLON = ntob(':') SEMICOLON = ntob(';') EMPTY = ntob('') NUMBER_SIGN = ntob('#') QUESTION_MARK = ntob('?') ASTERISK = ntob('*') FORWARD_SLASH = ntob('/') quoted_slash = re.compile(ntob('(?i)%2F')) def plat_specific_errors(*errnames): """Return error numbers for all errors in errnames on this platform. The 'errno' module contains different global constants depending on the specific platform (OS). This function will return the list of numeric values for a given list of potential names. """ errno_names = dir(errno) nums = [getattr(errno, k) for k in errnames if k in errno_names] # de-dupe the list return list(dict.fromkeys(nums).keys()) socket_error_eintr = plat_specific_errors('EINTR', 'WSAEINTR') socket_errors_to_ignore = plat_specific_errors( 'EPIPE', 'EBADF', 'WSAEBADF', 'ENOTSOCK', 'WSAENOTSOCK', 'ETIMEDOUT', 'WSAETIMEDOUT', 'ECONNREFUSED', 'WSAECONNREFUSED', 'ECONNRESET', 'WSAECONNRESET', 'ECONNABORTED', 'WSAECONNABORTED', 'ENETRESET', 'WSAENETRESET', 'EHOSTDOWN', 'EHOSTUNREACH', ) socket_errors_to_ignore.append('timed out') socket_errors_to_ignore.append('The read operation timed out') socket_errors_nonblocking = plat_specific_errors( 'EAGAIN', 'EWOULDBLOCK', 'WSAEWOULDBLOCK') if sys.platform == 'darwin': socket_errors_to_ignore.extend(plat_specific_errors('EPROTOTYPE')) socket_errors_nonblocking.extend(plat_specific_errors('EPROTOTYPE')) comma_separated_headers = [ ntob(h) for h in ['Accept', 'Accept-Charset', 'Accept-Encoding', 'Accept-Language', 'Accept-Ranges', 'Allow', 'Cache-Control', 'Connection', 'Content-Encoding', 'Content-Language', 'Expect', 'If-Match', 'If-None-Match', 'Pragma', 'Proxy-Authenticate', 'TE', 'Trailer', 'Transfer-Encoding', 'Upgrade', 'Vary', 'Via', 'Warning', 'WWW-Authenticate'] ] if not hasattr(logging, 'statistics'): logging.statistics = {} def read_headers(rfile, hdict=None): """Read headers from the given stream into the given header dict. If hdict is None, a new header dict is created. Returns the populated header dict. Headers which are repeated are folded together using a comma if their specification so dictates. This function raises ValueError when the read bytes violate the HTTP spec. You should probably return "400 Bad Request" if this happens. """ if hdict is None: hdict = {} while True: line = rfile.readline() if not line: # No more data--illegal end of headers raise ValueError('Illegal end of headers.') if line == CRLF: # Normal end of headers break if not line.endswith(CRLF): raise ValueError('HTTP requires CRLF terminators') if line[0] in (SPACE, TAB): # It's a continuation line. v = line.strip() else: try: k, v = line.split(COLON, 1) except ValueError: raise ValueError('Illegal header line.') # TODO: what about TE and WWW-Authenticate? k = k.strip().title() v = v.strip() hname = k if k in comma_separated_headers: existing = hdict.get(hname) if existing: v = b', '.join((existing, v)) hdict[hname] = v return hdict class MaxSizeExceeded(Exception): pass class SizeCheckWrapper(object): """Wraps a file-like object, raising MaxSizeExceeded if too large.""" def __init__(self, rfile, maxlen): self.rfile = rfile self.maxlen = maxlen self.bytes_read = 0 def _check_length(self): if self.maxlen and self.bytes_read > self.maxlen: raise MaxSizeExceeded() def read(self, size=None): data = self.rfile.read(size) self.bytes_read += len(data) self._check_length() return data def readline(self, size=None): if size is not None: data = self.rfile.readline(size) self.bytes_read += len(data) self._check_length() return data # User didn't specify a size ... # We read the line in chunks to make sure it's not a 100MB line ! res = [] while True: data = self.rfile.readline(256) self.bytes_read += len(data) self._check_length() res.append(data) # See https://github.com/cherrypy/cherrypy/issues/421 if len(data) < 256 or data[-1:] == LF: return EMPTY.join(res) def readlines(self, sizehint=0): # Shamelessly stolen from StringIO total = 0 lines = [] line = self.readline() while line: lines.append(line) total += len(line) if 0 < sizehint <= total: break line = self.readline() return lines def close(self): self.rfile.close() def __iter__(self): return self def __next__(self): data = next(self.rfile) self.bytes_read += len(data) self._check_length() return data def next(self): data = self.rfile.next() self.bytes_read += len(data) self._check_length() return data class KnownLengthRFile(object): """Wraps a file-like object, returning an empty string when exhausted.""" def __init__(self, rfile, content_length): self.rfile = rfile self.remaining = content_length def read(self, size=None): if self.remaining == 0: return b'' if size is None: size = self.remaining else: size = min(size, self.remaining) data = self.rfile.read(size) self.remaining -= len(data) return data def readline(self, size=None): if self.remaining == 0: return b'' if size is None: size = self.remaining else: size = min(size, self.remaining) data = self.rfile.readline(size) self.remaining -= len(data) return data def readlines(self, sizehint=0): # Shamelessly stolen from StringIO total = 0 lines = [] line = self.readline(sizehint) while line: lines.append(line) total += len(line) if 0 < sizehint <= total: break line = self.readline(sizehint) return lines def close(self): self.rfile.close() def __iter__(self): return self def __next__(self): data = next(self.rfile) self.remaining -= len(data) return data class ChunkedRFile(object): """Wraps a file-like object, returning an empty string when exhausted. This class is intended to provide a conforming wsgi.input value for request entities that have been encoded with the 'chunked' transfer encoding. """ def __init__(self, rfile, maxlen, bufsize=8192): self.rfile = rfile self.maxlen = maxlen self.bytes_read = 0 self.buffer = EMPTY self.bufsize = bufsize self.closed = False def _fetch(self): if self.closed: return line = self.rfile.readline() self.bytes_read += len(line) if self.maxlen and self.bytes_read > self.maxlen: raise MaxSizeExceeded('Request Entity Too Large', self.maxlen) line = line.strip().split(SEMICOLON, 1) try: chunk_size = line.pop(0) chunk_size = int(chunk_size, 16) except ValueError: raise ValueError('Bad chunked transfer size: ' + repr(chunk_size)) if chunk_size <= 0: self.closed = True return ## if line: chunk_extension = line[0] if self.maxlen and self.bytes_read + chunk_size > self.maxlen: raise IOError('Request Entity Too Large') chunk = self.rfile.read(chunk_size) self.bytes_read += len(chunk) self.buffer += chunk crlf = self.rfile.read(2) if crlf != CRLF: raise ValueError( "Bad chunked transfer coding (expected '\\r\\n', " 'got ' + repr(crlf) + ')') def read(self, size=None): data = EMPTY while True: if size and len(data) >= size: return data if not self.buffer: self._fetch() if not self.buffer: # EOF return data if size: remaining = size - len(data) data += self.buffer[:remaining] self.buffer = self.buffer[remaining:] else: data += self.buffer def readline(self, size=None): data = EMPTY while True: if size and len(data) >= size: return data if not self.buffer: self._fetch() if not self.buffer: # EOF return data newline_pos = self.buffer.find(LF) if size: if newline_pos == -1: remaining = size - len(data) data += self.buffer[:remaining] self.buffer = self.buffer[remaining:] else: remaining = min(size - len(data), newline_pos) data += self.buffer[:remaining] self.buffer = self.buffer[remaining:] else: if newline_pos == -1: data += self.buffer else: data += self.buffer[:newline_pos] self.buffer = self.buffer[newline_pos:] def readlines(self, sizehint=0): # Shamelessly stolen from StringIO total = 0 lines = [] line = self.readline(sizehint) while line: lines.append(line) total += len(line) if 0 < sizehint <= total: break line = self.readline(sizehint) return lines def read_trailer_lines(self): if not self.closed: raise ValueError( 'Cannot read trailers until the request body has been read.') while True: line = self.rfile.readline() if not line: # No more data--illegal end of headers raise ValueError('Illegal end of headers.') self.bytes_read += len(line) if self.maxlen and self.bytes_read > self.maxlen: raise IOError('Request Entity Too Large') if line == CRLF: # Normal end of headers break if not line.endswith(CRLF): raise ValueError('HTTP requires CRLF terminators') yield line def close(self): self.rfile.close() class HTTPRequest(object): """An HTTP Request (and response). A single HTTP connection may consist of multiple request/response pairs. """ server = None """The HTTPServer object which is receiving this request.""" conn = None """The HTTPConnection object on which this request connected.""" inheaders = {} """A dict of request headers.""" outheaders = [] """A list of header tuples to write in the response.""" ready = False """When True, the request has been parsed and is ready to begin generating the response. When False, signals the calling Connection that the response should not be generated and the connection should close.""" close_connection = False """Signals the calling Connection that the request should close. This does not imply an error! The client and/or server may each request that the connection be closed.""" chunked_write = False """If True, output will be encoded with the "chunked" transfer-coding. This value is set automatically inside send_headers.""" def __init__(self, server, conn): self.server = server self.conn = conn self.ready = False self.started_request = False self.scheme = ntob('http') if self.server.ssl_adapter is not None: self.scheme = ntob('https') # Use the lowest-common protocol in case read_request_line errors. self.response_protocol = 'HTTP/1.0' self.inheaders = {} self.status = '' self.outheaders = [] self.sent_headers = False self.close_connection = self.__class__.close_connection self.chunked_read = False self.chunked_write = self.__class__.chunked_write def parse_request(self): """Parse the next HTTP request start-line and message-headers.""" self.rfile = SizeCheckWrapper(self.conn.rfile, self.server.max_request_header_size) try: success = self.read_request_line() except MaxSizeExceeded: self.simple_response( '414 Request-URI Too Long', 'The Request-URI sent with the request exceeds the maximum ' 'allowed bytes.') return else: if not success: return try: success = self.read_request_headers() except MaxSizeExceeded: self.simple_response( '413 Request Entity Too Large', 'The headers sent with the request exceed the maximum ' 'allowed bytes.') return else: if not success: return self.ready = True def read_request_line(self): # HTTP/1.1 connections are persistent by default. If a client # requests a page, then idles (leaves the connection open), # then rfile.readline() will raise socket.error("timed out"). # Note that it does this based on the value given to settimeout(), # and doesn't need the client to request or acknowledge the close # (although your TCP stack might suffer for it: cf Apache's history # with FIN_WAIT_2). request_line = self.rfile.readline() # Set started_request to True so communicate() knows to send 408 # from here on out. self.started_request = True if not request_line: return False if request_line == CRLF: # RFC 2616 sec 4.1: "...if the server is reading the protocol # stream at the beginning of a message and receives a CRLF # first, it should ignore the CRLF." # But only ignore one leading line! else we enable a DoS. request_line = self.rfile.readline() if not request_line: return False if not request_line.endswith(CRLF): self.simple_response( '400 Bad Request', 'HTTP requires CRLF terminators') return False try: method, uri, req_protocol = request_line.strip().split(SPACE, 2) req_protocol_str = req_protocol.decode('ascii') rp = int(req_protocol_str[5]), int(req_protocol_str[7]) except (ValueError, IndexError): self.simple_response('400 Bad Request', 'Malformed Request-Line') return False self.uri = uri self.method = method # uri may be an abs_path (including "http://host.domain.tld"); scheme, authority, path = self.parse_request_uri(uri) if path is None: self.simple_response('400 Bad Request', 'Invalid path in Request-URI.') return False if NUMBER_SIGN in path: self.simple_response('400 Bad Request', 'Illegal #fragment in Request-URI.') return False if scheme: self.scheme = scheme qs = EMPTY if QUESTION_MARK in path: path, qs = path.split(QUESTION_MARK, 1) # Unquote the path+params (e.g. "/this%20path" -> "/this path"). # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2 # # But note that "...a URI must be separated into its components # before the escaped characters within those components can be # safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2 # Therefore, "/this%2Fpath" becomes "/this%2Fpath", not "/this/path". try: atoms = [unquote_to_bytes(x) for x in quoted_slash.split(path)] except ValueError: ex = sys.exc_info()[1] self.simple_response('400 Bad Request', ex.args[0]) return False path = b'%2F'.join(atoms) self.path = path # Note that, like wsgiref and most other HTTP servers, # we "% HEX HEX"-unquote the path but not the query string. self.qs = qs # Compare request and server HTTP protocol versions, in case our # server does not support the requested protocol. Limit our output # to min(req, server). We want the following output: # request server actual written supported response # protocol protocol response protocol feature set # a 1.0 1.0 1.0 1.0 # b 1.0 1.1 1.1 1.0 # c 1.1 1.0 1.0 1.0 # d 1.1 1.1 1.1 1.1 # Notice that, in (b), the response will be "HTTP/1.1" even though # the client only understands 1.0. RFC 2616 10.5.6 says we should # only return 505 if the _major_ version is different. sp = int(self.server.protocol[5]), int(self.server.protocol[7]) if sp[0] != rp[0]: self.simple_response('505 HTTP Version Not Supported') return False self.request_protocol = req_protocol self.response_protocol = 'HTTP/%s.%s' % min(rp, sp) return True def read_request_headers(self): """Read self.rfile into self.inheaders. Return success.""" # then all the http headers try: read_headers(self.rfile, self.inheaders) except ValueError: ex = sys.exc_info()[1] self.simple_response('400 Bad Request', ex.args[0]) return False mrbs = self.server.max_request_body_size if mrbs and int(self.inheaders.get(b'Content-Length', 0)) > mrbs: self.simple_response( '413 Request Entity Too Large', 'The entity sent with the request exceeds the maximum ' 'allowed bytes.') return False # Persistent connection support if self.response_protocol == 'HTTP/1.1': # Both server and client are HTTP/1.1 if self.inheaders.get(b'Connection', b'') == b'close': self.close_connection = True else: # Either the server or client (or both) are HTTP/1.0 if self.inheaders.get(b'Connection', b'') != b'Keep-Alive': self.close_connection = True # Transfer-Encoding support te = None if self.response_protocol == 'HTTP/1.1': te = self.inheaders.get(b'Transfer-Encoding') if te: te = [x.strip().lower() for x in te.split(b',') if x.strip()] self.chunked_read = False if te: for enc in te: if enc == b'chunked': self.chunked_read = True else: # Note that, even if we see "chunked", we must reject # if there is an extension we don't recognize. self.simple_response('501 Unimplemented') self.close_connection = True return False # From PEP 333: # "Servers and gateways that implement HTTP 1.1 must provide # transparent support for HTTP 1.1's "expect/continue" mechanism. # This may be done in any of several ways: # 1. Respond to requests containing an Expect: 100-continue request # with an immediate "100 Continue" response, and proceed normally. # 2. Proceed with the request normally, but provide the application # with a wsgi.input stream that will send the "100 Continue" # response if/when the application first attempts to read from # the input stream. The read request must then remain blocked # until the client responds. # 3. Wait until the client decides that the server does not support # expect/continue, and sends the request body on its own. # (This is suboptimal, and is not recommended.) # # We used to do 3, but are now doing 1. Maybe we'll do 2 someday, # but it seems like it would be a big slowdown for such a rare case. if self.inheaders.get(b'Expect', b'') == b'100-continue': # Don't use simple_response here, because it emits headers # we don't want. See # https://github.com/cherrypy/cherrypy/issues/951 msg = self.server.protocol.encode('ascii') msg += b' 100 Continue\r\n\r\n' try: self.conn.wfile.write(msg) except socket.error: x = sys.exc_info()[1] if x.args[0] not in socket_errors_to_ignore: raise return True def parse_request_uri(self, uri): """Parse a Request-URI into (scheme, authority, path). Note that Request-URI's must be one of:: Request-URI = "*" | absoluteURI | abs_path | authority Therefore, a Request-URI which starts with a double forward-slash cannot be a "net_path":: net_path = "//" authority [ abs_path ] Instead, it must be interpreted as an "abs_path" with an empty first path segment:: abs_path = "/" path_segments path_segments = segment *( "/" segment ) segment = *pchar *( ";" param ) param = *pchar """ if uri == ASTERISK: return None, None, uri scheme, authority, path, params, query, fragment = urlparse(uri) if scheme and QUESTION_MARK not in scheme: # An absoluteURI. # If there's a scheme (and it must be http or https), then: # http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query # ]] return scheme, authority, path if uri.startswith(FORWARD_SLASH): # An abs_path. return None, None, uri else: # An authority. return None, uri, None def respond(self): """Call the gateway and write its iterable output.""" mrbs = self.server.max_request_body_size if self.chunked_read: self.rfile = ChunkedRFile(self.conn.rfile, mrbs) else: cl = int(self.inheaders.get(b'Content-Length', 0)) if mrbs and mrbs < cl: if not self.sent_headers: self.simple_response( '413 Request Entity Too Large', 'The entity sent with the request exceeds the ' 'maximum allowed bytes.') return self.rfile = KnownLengthRFile(self.conn.rfile, cl) self.server.gateway(self).respond() if (self.ready and not self.sent_headers): self.sent_headers = True self.send_headers() if self.chunked_write: self.conn.wfile.write(b'0\r\n\r\n') def simple_response(self, status, msg=''): """Write a simple response back to the client.""" status = str(status) proto_status = '%s %s\r\n' % (self.server.protocol, status) content_length = 'Content-Length: %s\r\n' % len(msg) content_type = 'Content-Type: text/plain\r\n' buf = [ proto_status.encode('ISO-8859-1'), content_length.encode('ISO-8859-1'), content_type.encode('ISO-8859-1'), ] if status[:3] in ('413', '414'): # Request Entity Too Large / Request-URI Too Long self.close_connection = True if self.response_protocol == 'HTTP/1.1': # This will not be true for 414, since read_request_line # usually raises 414 before reading the whole line, and we # therefore cannot know the proper response_protocol. buf.append(b'Connection: close\r\n') else: # HTTP/1.0 had no 413/414 status nor Connection header. # Emit 400 instead and trust the message body is enough. status = '400 Bad Request' buf.append(CRLF) if msg: if isinstance(msg, six.text_type): msg = msg.encode('ISO-8859-1') buf.append(msg) try: self.conn.wfile.write(EMPTY.join(buf)) except socket.error: x = sys.exc_info()[1] if x.args[0] not in socket_errors_to_ignore: raise def write(self, chunk): """Write unbuffered data to the client.""" if self.chunked_write and chunk: chunk_size_hex = hex(len(chunk))[2:].encode('ascii') buf = [chunk_size_hex, CRLF, chunk, CRLF] self.conn.wfile.write(EMPTY.join(buf)) else: self.conn.wfile.write(chunk) def send_headers(self): """Assert, process, and send the HTTP response message-headers. You must set self.status, and self.outheaders before calling this. """ hkeys = [key.lower() for key, value in self.outheaders] status = int(self.status[:3]) if status == 413: # Request Entity Too Large. Close conn to avoid garbage. self.close_connection = True elif b'content-length' not in hkeys: # "All 1xx (informational), 204 (no content), # and 304 (not modified) responses MUST NOT # include a message-body." So no point chunking. if status < 200 or status in (204, 205, 304): pass else: if (self.response_protocol == 'HTTP/1.1' and self.method != b'HEAD'): # Use the chunked transfer-coding self.chunked_write = True self.outheaders.append((b'Transfer-Encoding', b'chunked')) else: # Closing the conn is the only way to determine len. self.close_connection = True if b'connection' not in hkeys: if self.response_protocol == 'HTTP/1.1': # Both server and client are HTTP/1.1 or better if self.close_connection: self.outheaders.append((b'Connection', b'close')) else: # Server and/or client are HTTP/1.0 if not self.close_connection: self.outheaders.append((b'Connection', b'Keep-Alive')) if (not self.close_connection) and (not self.chunked_read): # Read any remaining request body data on the socket. # "If an origin server receives a request that does not include an # Expect request-header field with the "100-continue" expectation, # the request includes a request body, and the server responds # with a final status code before reading the entire request body # from the transport connection, then the server SHOULD NOT close # the transport connection until it has read the entire request, # or until the client closes the connection. Otherwise, the client # might not reliably receive the response message. However, this # requirement is not be construed as preventing a server from # defending itself against denial-of-service attacks, or from # badly broken client implementations." remaining = getattr(self.rfile, 'remaining', 0) if remaining > 0: self.rfile.read(remaining) if b'date' not in hkeys: self.outheaders.append(( b'Date', email.utils.formatdate(usegmt=True).encode('ISO-8859-1'), )) if b'server' not in hkeys: self.outheaders.append(( b'Server', self.server.server_name.encode('ISO-8859-1'), )) proto = self.server.protocol.encode('ascii') buf = [proto + SPACE + self.status + CRLF] for k, v in self.outheaders: buf.append(k + COLON + SPACE + v + CRLF) buf.append(CRLF) self.conn.wfile.write(EMPTY.join(buf)) class NoSSLError(Exception): """Exception raised when a client speaks HTTP to an HTTPS socket.""" pass class FatalSSLAlert(Exception): """Exception raised when the SSL implementation signals a fatal alert.""" pass class CP_BufferedWriter(io.BufferedWriter): """Faux file object attached to a socket object.""" def write(self, b): self._checkClosed() if isinstance(b, str): raise TypeError("can't write str to binary stream") with self._write_lock: self._write_buf.extend(b) self._flush_unlocked() return len(b) def _flush_unlocked(self): self._checkClosed('flush of closed file') while self._write_buf: try: # ssl sockets only except 'bytes', not bytearrays # so perhaps we should conditionally wrap this for perf? n = self.raw.write(bytes(self._write_buf)) except io.BlockingIOError as e: n = e.characters_written del self._write_buf[:n] def CP_makefile_PY3(sock, mode='r', bufsize=DEFAULT_BUFFER_SIZE): if 'r' in mode: return io.BufferedReader(socket.SocketIO(sock, mode), bufsize) else: return CP_BufferedWriter(socket.SocketIO(sock, mode), bufsize) class CP_makefile_PY2(getattr(socket, '_fileobject', object)): """Faux file object attached to a socket object.""" def __init__(self, *args, **kwargs): self.bytes_read = 0 self.bytes_written = 0 socket._fileobject.__init__(self, *args, **kwargs) def write(self, data): """Sendall for non-blocking sockets.""" while data: try: bytes_sent = self.send(data) data = data[bytes_sent:] except socket.error as e: if e.args[0] not in socket_errors_nonblocking: raise def send(self, data): bytes_sent = self._sock.send(data) self.bytes_written += bytes_sent return bytes_sent def flush(self): if self._wbuf: buffer = ''.join(self._wbuf) self._wbuf = [] self.write(buffer) def recv(self, size): while True: try: data = self._sock.recv(size) self.bytes_read += len(data) return data except socket.error as e: # Catch 'unknown ca' errors from builtin SSL-adapter if len(e.args) > 1 and 'unknown ca' in e.args[1]: return if (e.args[0] not in socket_errors_nonblocking and e.args[0] not in socket_error_eintr): raise class FauxSocket(object): """Faux socket with the minimal interface required by pypy""" def _reuse(self): pass _fileobject_uses_str_type = six.PY2 and isinstance( socket._fileobject(FauxSocket())._rbuf, six.string_types) # FauxSocket is no longer needed del FauxSocket if not _fileobject_uses_str_type: def read(self, size=-1): # Use max, disallow tiny reads in a loop as they are very # inefficient. # We never leave read() with any leftover data from a new recv() # call in our internal buffer. rbufsize = max(self._rbufsize, self.default_bufsize) # Our use of StringIO rather than lists of string objects returned # by recv() minimizes memory usage and fragmentation that occurs # when rbufsize is large compared to the typical return value of # recv(). buf = self._rbuf buf.seek(0, 2) # seek end if size < 0: # Read until EOF # reset _rbuf. we consume it via buf. self._rbuf = io.BytesIO() while True: data = self.recv(rbufsize) if not data: break buf.write(data) return buf.getvalue() else: # Read until size bytes or EOF seen, whichever comes first buf_len = buf.tell() if buf_len >= size: # Already have size bytes in our buffer? Extract and # return. buf.seek(0) rv = buf.read(size) self._rbuf = io.BytesIO() self._rbuf.write(buf.read()) return rv # reset _rbuf. we consume it via buf. self._rbuf = io.BytesIO() while True: left = size - buf_len # recv() will malloc the amount of memory given as its # parameter even though it often returns much less data # than that. The returned data string is short lived # as we copy it into a StringIO and free it. This avoids # fragmentation issues on many platforms. data = self.recv(left) if not data: break n = len(data) if n == size and not buf_len: # Shortcut. Avoid buffer data copies when: # - We have no data in our buffer. # AND # - Our call to recv returned exactly the # number of bytes we were asked to read. return data if n == left: buf.write(data) del data # explicit free break assert n <= left, 'recv(%d) returned %d bytes' % (left, n) buf.write(data) buf_len += n del data # explicit free # assert buf_len == buf.tell() return buf.getvalue() def readline(self, size=-1): buf = self._rbuf buf.seek(0, 2) # seek end if buf.tell() > 0: # check if we already have it in our buffer buf.seek(0) bline = buf.readline(size) if bline.endswith('\n') or len(bline) == size: self._rbuf = io.BytesIO() self._rbuf.write(buf.read()) return bline del bline if size < 0: # Read until \n or EOF, whichever comes first if self._rbufsize <= 1: # Speed up unbuffered case buf.seek(0) buffers = [buf.read()] # reset _rbuf. we consume it via buf. self._rbuf = io.BytesIO() data = None recv = self.recv while data != '\n': data = recv(1) if not data: break buffers.append(data) return ''.join(buffers) buf.seek(0, 2) # seek end # reset _rbuf. we consume it via buf. self._rbuf = io.BytesIO() while True: data = self.recv(self._rbufsize) if not data: break nl = data.find('\n') if nl >= 0: nl += 1 buf.write(data[:nl]) self._rbuf.write(data[nl:]) del data break buf.write(data) return buf.getvalue() else: # Read until size bytes or \n or EOF seen, whichever comes # first buf.seek(0, 2) # seek end buf_len = buf.tell() if buf_len >= size: buf.seek(0) rv = buf.read(size) self._rbuf = io.BytesIO() self._rbuf.write(buf.read()) return rv # reset _rbuf. we consume it via buf. self._rbuf = io.BytesIO() while True: data = self.recv(self._rbufsize) if not data: break left = size - buf_len # did we just receive a newline? nl = data.find('\n', 0, left) if nl >= 0: nl += 1 # save the excess data to _rbuf self._rbuf.write(data[nl:]) if buf_len: buf.write(data[:nl]) break else: # Shortcut. Avoid data copy through buf when # returning a substring of our first recv(). return data[:nl] n = len(data) if n == size and not buf_len: # Shortcut. Avoid data copy through buf when # returning exactly all of our first recv(). return data if n >= left: buf.write(data[:left]) self._rbuf.write(data[left:]) break buf.write(data) buf_len += n # assert buf_len == buf.tell() return buf.getvalue() else: def read(self, size=-1): if size < 0: # Read until EOF buffers = [self._rbuf] self._rbuf = '' if self._rbufsize <= 1: recv_size = self.default_bufsize else: recv_size = self._rbufsize while True: data = self.recv(recv_size) if not data: break buffers.append(data) return ''.join(buffers) else: # Read until size bytes or EOF seen, whichever comes first data = self._rbuf buf_len = len(data) if buf_len >= size: self._rbuf = data[size:] return data[:size] buffers = [] if data: buffers.append(data) self._rbuf = '' while True: left = size - buf_len recv_size = max(self._rbufsize, left) data = self.recv(recv_size) if not data: break buffers.append(data) n = len(data) if n >= left: self._rbuf = data[left:] buffers[-1] = data[:left] break buf_len += n return ''.join(buffers) def readline(self, size=-1): data = self._rbuf if size < 0: # Read until \n or EOF, whichever comes first if self._rbufsize <= 1: # Speed up unbuffered case assert data == '' buffers = [] while data != '\n': data = self.recv(1) if not data: break buffers.append(data) return ''.join(buffers) nl = data.find('\n') if nl >= 0: nl += 1 self._rbuf = data[nl:] return data[:nl] buffers = [] if data: buffers.append(data) self._rbuf = '' while True: data = self.recv(self._rbufsize) if not data: break buffers.append(data) nl = data.find('\n') if nl >= 0: nl += 1 self._rbuf = data[nl:] buffers[-1] = data[:nl] break return ''.join(buffers) else: # Read until size bytes or \n or EOF seen, whichever comes # first nl = data.find('\n', 0, size) if nl >= 0: nl += 1 self._rbuf = data[nl:] return data[:nl] buf_len = len(data) if buf_len >= size: self._rbuf = data[size:] return data[:size] buffers = [] if data: buffers.append(data) self._rbuf = '' while True: data = self.recv(self._rbufsize) if not data: break buffers.append(data) left = size - buf_len nl = data.find('\n', 0, left) if nl >= 0: nl += 1 self._rbuf = data[nl:] buffers[-1] = data[:nl] break n = len(data) if n >= left: self._rbuf = data[left:] buffers[-1] = data[:left] break buf_len += n return ''.join(buffers) CP_makefile = CP_makefile_PY2 if six.PY2 else CP_makefile_PY3 class HTTPConnection(object): """An HTTP connection (active socket). server: the Server object which received this connection. socket: the raw socket object (usually TCP) for this connection. makefile: a fileobject class for reading from the socket. """ remote_addr = None remote_port = None ssl_env = None rbufsize = DEFAULT_BUFFER_SIZE wbufsize = DEFAULT_BUFFER_SIZE RequestHandlerClass = HTTPRequest def __init__(self, server, sock, makefile=CP_makefile): self.server = server self.socket = sock self.rfile = makefile(sock, 'rb', self.rbufsize) self.wfile = makefile(sock, 'wb', self.wbufsize) self.requests_seen = 0 def communicate(self): """Read each request and respond appropriately.""" request_seen = False try: while True: # (re)set req to None so that if something goes wrong in # the RequestHandlerClass constructor, the error doesn't # get written to the previous request. req = None req = self.RequestHandlerClass(self.server, self) # This order of operations should guarantee correct pipelining. req.parse_request() if self.server.stats['Enabled']: self.requests_seen += 1 if not req.ready: # Something went wrong in the parsing (and the server has # probably already made a simple_response). Return and # let the conn close. return request_seen = True req.respond() if req.close_connection: return except socket.error: e = sys.exc_info()[1] errnum = e.args[0] # sadly SSL sockets return a different (longer) time out string if ( errnum == 'timed out' or errnum == 'The read operation timed out' ): # Don't error if we're between requests; only error # if 1) no request has been started at all, or 2) we're # in the middle of a request. # See https://github.com/cherrypy/cherrypy/issues/853 if (not request_seen) or (req and req.started_request): # Don't bother writing the 408 if the response # has already started being written. if req and not req.sent_headers: try: req.simple_response('408 Request Timeout') except FatalSSLAlert: # Close the connection. return except NoSSLError: self._handle_no_ssl() elif errnum not in socket_errors_to_ignore: self.server.error_log('socket.error %s' % repr(errnum), level=logging.WARNING, traceback=True) if req and not req.sent_headers: try: req.simple_response('500 Internal Server Error') except FatalSSLAlert: # Close the connection. return except NoSSLError: self._handle_no_ssl() return except (KeyboardInterrupt, SystemExit): raise except FatalSSLAlert: # Close the connection. return except NoSSLError: self._handle_no_ssl(req) except Exception: e = sys.exc_info()[1] self.server.error_log(repr(e), level=logging.ERROR, traceback=True) if req and not req.sent_headers: try: req.simple_response('500 Internal Server Error') except FatalSSLAlert: # Close the connection. return linger = False def _handle_no_ssl(self, req): if not req or req.sent_headers: return # Unwrap wfile self.wfile = CP_makefile(self.socket._sock, 'wb', self.wbufsize) msg = ( 'The client sent a plain HTTP request, but ' 'this server only speaks HTTPS on this port.' ) req.simple_response('400 Bad Request', msg) self.linger = True def close(self): """Close the socket underlying this connection.""" self.rfile.close() if not self.linger: self._close_kernel_socket() self.socket.close() else: # On the other hand, sometimes we want to hang around for a bit # to make sure the client has a chance to read our entire # response. Skipping the close() calls here delays the FIN # packet until the socket object is garbage-collected later. # Someday, perhaps, we'll do the full lingering_close that # Apache does, but not today. pass def _close_kernel_socket(self): """ On old Python versions, Python's socket module does NOT call close on the kernel socket when you call socket.close(). We do so manually here because we want this server to send a FIN TCP segment immediately. Note this must be called *before* calling socket.close(), because the latter drops its reference to the kernel socket. """ if six.PY2 and hasattr(self.socket, '_sock'): self.socket._sock.close() class TrueyZero(object): """An object which equals and does math like the integer 0 but evals True. """ def __add__(self, other): return other def __radd__(self, other): return other trueyzero = TrueyZero() _SHUTDOWNREQUEST = None class WorkerThread(threading.Thread): """Thread which continuously polls a Queue for Connection objects. Due to the timing issues of polling a Queue, a WorkerThread does not check its own 'ready' flag after it has started. To stop the thread, it is necessary to stick a _SHUTDOWNREQUEST object onto the Queue (one for each running WorkerThread). """ conn = None """The current connection pulled off the Queue, or None.""" server = None """The HTTP Server which spawned this thread, and which owns the Queue and is placing active connections into it.""" ready = False """A simple flag for the calling server to know when this thread has begun polling the Queue.""" def __init__(self, server): self.ready = False self.server = server self.requests_seen = 0 self.bytes_read = 0 self.bytes_written = 0 self.start_time = None self.work_time = 0 self.stats = { 'Requests': lambda s: self.requests_seen + ( (self.start_time is None) and trueyzero or self.conn.requests_seen ), 'Bytes Read': lambda s: self.bytes_read + ( (self.start_time is None) and trueyzero or self.conn.rfile.bytes_read ), 'Bytes Written': lambda s: self.bytes_written + ( (self.start_time is None) and trueyzero or self.conn.wfile.bytes_written ), 'Work Time': lambda s: self.work_time + ( (self.start_time is None) and trueyzero or time.time() - self.start_time ), 'Read Throughput': lambda s: s['Bytes Read'](s) / ( s['Work Time'](s) or 1e-6), 'Write Throughput': lambda s: s['Bytes Written'](s) / ( s['Work Time'](s) or 1e-6), } threading.Thread.__init__(self) def run(self): self.server.stats['Worker Threads'][self.getName()] = self.stats try: self.ready = True while True: conn = self.server.requests.get() if conn is _SHUTDOWNREQUEST: return self.conn = conn if self.server.stats['Enabled']: self.start_time = time.time() try: conn.communicate() finally: conn.close() if self.server.stats['Enabled']: self.requests_seen += self.conn.requests_seen self.bytes_read += self.conn.rfile.bytes_read self.bytes_written += self.conn.wfile.bytes_written self.work_time += time.time() - self.start_time self.start_time = None self.conn = None except (KeyboardInterrupt, SystemExit): exc = sys.exc_info()[1] self.server.interrupt = exc class ThreadPool(object): """A Request Queue for an HTTPServer which pools threads. ThreadPool objects must provide min, get(), put(obj), start() and stop(timeout) attributes. """ def __init__(self, server, min=10, max=-1, accepted_queue_size=-1, accepted_queue_timeout=10): self.server = server self.min = min self.max = max self._threads = [] self._queue = queue.Queue(maxsize=accepted_queue_size) self._queue_put_timeout = accepted_queue_timeout self.get = self._queue.get def start(self): """Start the pool of threads.""" for i in range(self.min): self._threads.append(WorkerThread(self.server)) for worker in self._threads: worker.setName('CP Server ' + worker.getName()) worker.start() for worker in self._threads: while not worker.ready: time.sleep(.1) def _get_idle(self): """Number of worker threads which are idle. Read-only.""" return len([t for t in self._threads if t.conn is None]) idle = property(_get_idle, doc=_get_idle.__doc__) def put(self, obj): self._queue.put(obj, block=True, timeout=self._queue_put_timeout) if obj is _SHUTDOWNREQUEST: return def grow(self, amount): """Spawn new worker threads (not above self.max).""" if self.max > 0: budget = max(self.max - len(self._threads), 0) else: # self.max <= 0 indicates no maximum budget = float('inf') n_new = min(amount, budget) workers = [self._spawn_worker() for i in range(n_new)] while not all(worker.ready for worker in workers): time.sleep(.1) self._threads.extend(workers) def _spawn_worker(self): worker = WorkerThread(self.server) worker.setName('CP Server ' + worker.getName()) worker.start() return worker def shrink(self, amount): """Kill off worker threads (not below self.min).""" # Grow/shrink the pool if necessary. # Remove any dead threads from our list for t in self._threads: if not t.isAlive(): self._threads.remove(t) amount -= 1 # calculate the number of threads above the minimum n_extra = max(len(self._threads) - self.min, 0) # don't remove more than amount n_to_remove = min(amount, n_extra) # put shutdown requests on the queue equal to the number of threads # to remove. As each request is processed by a worker, that worker # will terminate and be culled from the list. for n in range(n_to_remove): self._queue.put(_SHUTDOWNREQUEST) def stop(self, timeout=5): # Must shut down threads here so the code that calls # this method can know when all threads are stopped. for worker in self._threads: self._queue.put(_SHUTDOWNREQUEST) # Don't join currentThread (when stop is called inside a request). current = threading.currentThread() if timeout is not None and timeout >= 0: endtime = time.time() + timeout while self._threads: worker = self._threads.pop() if worker is not current and worker.isAlive(): try: if timeout is None or timeout < 0: worker.join() else: remaining_time = endtime - time.time() if remaining_time > 0: worker.join(remaining_time) if worker.isAlive(): # We exhausted the timeout. # Forcibly shut down the socket. c = worker.conn if c and not c.rfile.closed: try: c.socket.shutdown(socket.SHUT_RD) except TypeError: # pyOpenSSL sockets don't take an arg c.socket.shutdown() worker.join() except (AssertionError, # Ignore repeated Ctrl-C. # See # https://github.com/cherrypy/cherrypy/issues/691. KeyboardInterrupt): pass def _get_qsize(self): return self._queue.qsize() qsize = property(_get_qsize) try: import fcntl except ImportError: try: from ctypes import windll, WinError import ctypes.wintypes _SetHandleInformation = windll.kernel32.SetHandleInformation _SetHandleInformation.argtypes = [ ctypes.wintypes.HANDLE, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ] _SetHandleInformation.restype = ctypes.wintypes.BOOL except ImportError: def prevent_socket_inheritance(sock): """Dummy function, since neither fcntl nor ctypes are available.""" pass else: def prevent_socket_inheritance(sock): """Mark the given socket fd as non-inheritable (Windows).""" if not _SetHandleInformation(sock.fileno(), 1, 0): raise WinError() else: def prevent_socket_inheritance(sock): """Mark the given socket fd as non-inheritable (POSIX).""" fd = sock.fileno() old_flags = fcntl.fcntl(fd, fcntl.F_GETFD) fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC) class SSLAdapter(object): """Base class for SSL driver library adapters. Required methods: * ``wrap(sock) -> (wrapped socket, ssl environ dict)`` * ``makefile(sock, mode='r', bufsize=DEFAULT_BUFFER_SIZE) -> socket file object`` """ def __init__(self, certificate, private_key, certificate_chain=None): self.certificate = certificate self.private_key = private_key self.certificate_chain = certificate_chain def wrap(self, sock): raise NotImplemented def makefile(self, sock, mode='r', bufsize=DEFAULT_BUFFER_SIZE): raise NotImplemented class HTTPServer(object): """An HTTP server.""" _bind_addr = '127.0.0.1' _interrupt = None gateway = None """A Gateway instance.""" minthreads = None """The minimum number of worker threads to create (default 10).""" maxthreads = None """The maximum number of worker threads to create (default -1 = no limit). """ server_name = None """The name of the server; defaults to socket.gethostname().""" protocol = 'HTTP/1.1' """The version string to write in the Status-Line of all HTTP responses. For example, "HTTP/1.1" is the default. This also limits the supported features used in the response.""" request_queue_size = 5 """The 'backlog' arg to socket.listen(); max queued connections (default 5). """ shutdown_timeout = 5 """The total time, in seconds, to wait for worker threads to cleanly exit. """ timeout = 10 """The timeout in seconds for accepted connections (default 10).""" version = 'CherryPy/' + cp_version """A version string for the HTTPServer.""" software = None """The value to set for the SERVER_SOFTWARE entry in the WSGI environ. If None, this defaults to ``'%s Server' % self.version``.""" ready = False """An internal flag which marks whether the socket is accepting connections. """ max_request_header_size = 0 """The maximum size, in bytes, for request headers, or 0 for no limit.""" max_request_body_size = 0 """The maximum size, in bytes, for request bodies, or 0 for no limit.""" nodelay = True """If True (the default since 3.1), sets the TCP_NODELAY socket option.""" ConnectionClass = HTTPConnection """The class to use for handling HTTP connections.""" ssl_adapter = None """An instance of SSLAdapter (or a subclass). You must have the corresponding SSL driver library installed.""" def __init__(self, bind_addr, gateway, minthreads=10, maxthreads=-1, server_name=None): self.bind_addr = bind_addr self.gateway = gateway self.requests = ThreadPool(self, min=minthreads or 1, max=maxthreads) if not server_name: server_name = socket.gethostname() self.server_name = server_name self.clear_stats() def clear_stats(self): self._start_time = None self._run_time = 0 self.stats = { 'Enabled': False, 'Bind Address': lambda s: repr(self.bind_addr), 'Run time': lambda s: (not s['Enabled']) and -1 or self.runtime(), 'Accepts': 0, 'Accepts/sec': lambda s: s['Accepts'] / self.runtime(), 'Queue': lambda s: getattr(self.requests, 'qsize', None), 'Threads': lambda s: len(getattr(self.requests, '_threads', [])), 'Threads Idle': lambda s: getattr(self.requests, 'idle', None), 'Socket Errors': 0, 'Requests': lambda s: (not s['Enabled']) and -1 or sum( [w['Requests'](w) for w in s['Worker Threads'].values()], 0), 'Bytes Read': lambda s: (not s['Enabled']) and -1 or sum( [w['Bytes Read'](w) for w in s['Worker Threads'].values()], 0), 'Bytes Written': lambda s: (not s['Enabled']) and -1 or sum( [w['Bytes Written'](w) for w in s['Worker Threads'].values()], 0), 'Work Time': lambda s: (not s['Enabled']) and -1 or sum( [w['Work Time'](w) for w in s['Worker Threads'].values()], 0), 'Read Throughput': lambda s: (not s['Enabled']) and -1 or sum( [w['Bytes Read'](w) / (w['Work Time'](w) or 1e-6) for w in s['Worker Threads'].values()], 0), 'Write Throughput': lambda s: (not s['Enabled']) and -1 or sum( [w['Bytes Written'](w) / (w['Work Time'](w) or 1e-6) for w in s['Worker Threads'].values()], 0), 'Worker Threads': {}, } logging.statistics['CherryPy HTTPServer %d' % id(self)] = self.stats def runtime(self): if self._start_time is None: return self._run_time else: return self._run_time + (time.time() - self._start_time) def __str__(self): return '%s.%s(%r)' % (self.__module__, self.__class__.__name__, self.bind_addr) def _get_bind_addr(self): return self._bind_addr def _set_bind_addr(self, value): if isinstance(value, tuple) and value[0] in ('', None): # Despite the socket module docs, using '' does not # allow AI_PASSIVE to work. Passing None instead # returns '0.0.0.0' like we want. In other words: # host AI_PASSIVE result # '' Y 192.168.x.y # '' N 192.168.x.y # None Y 0.0.0.0 # None N 127.0.0.1 # But since you can get the same effect with an explicit # '0.0.0.0', we deny both the empty string and None as values. raise ValueError("Host values of '' or None are not allowed. " "Use '0.0.0.0' (IPv4) or '::' (IPv6) instead " 'to listen on all active interfaces.') self._bind_addr = value bind_addr = property( _get_bind_addr, _set_bind_addr, doc="""The interface on which to listen for connections. For TCP sockets, a (host, port) tuple. Host values may be any IPv4 or IPv6 address, or any valid hostname. The string 'localhost' is a synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6). The string '0.0.0.0' is a special IPv4 entry meaning "any active interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for IPv6. The empty string or None are not allowed. For UNIX sockets, supply the filename as a string. Systemd socket activation is automatic and doesn't require tempering with this variable""") def start(self): """Run the server forever.""" # We don't have to trap KeyboardInterrupt or SystemExit here, # because cherrpy.server already does so, calling self.stop() for us. # If you're using this server with another framework, you should # trap those exceptions in whatever code block calls start(). self._interrupt = None if self.software is None: self.software = '%s Server' % self.version # Select the appropriate socket self.socket = None if os.getenv('LISTEN_PID', None): # systemd socket activation self.socket = socket.fromfd(3, socket.AF_INET, socket.SOCK_STREAM) elif isinstance(self.bind_addr, six.string_types): # AF_UNIX socket # So we can reuse the socket... try: os.unlink(self.bind_addr) except: pass # So everyone can access the socket... try: os.chmod(self.bind_addr, 0o777) except: pass info = [ (socket.AF_UNIX, socket.SOCK_STREAM, 0, '', self.bind_addr)] else: # AF_INET or AF_INET6 socket # Get the correct address family for our host (allows IPv6 # addresses) host, port = self.bind_addr try: info = socket.getaddrinfo( host, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) except socket.gaierror: if ':' in self.bind_addr[0]: info = [(socket.AF_INET6, socket.SOCK_STREAM, 0, '', self.bind_addr + (0, 0))] else: info = [(socket.AF_INET, socket.SOCK_STREAM, 0, '', self.bind_addr)] if not self.socket: msg = 'No socket could be created' for res in info: af, socktype, proto, canonname, sa = res try: self.bind(af, socktype, proto) break except socket.error as serr: msg = '%s -- (%s: %s)' % (msg, sa, serr) if self.socket: self.socket.close() self.socket = None if not self.socket: raise socket.error(msg) # Timeout so KeyboardInterrupt can be caught on Win32 self.socket.settimeout(1) self.socket.listen(self.request_queue_size) # Create worker threads self.requests.start() self.ready = True self._start_time = time.time() while self.ready: try: self.tick() except (KeyboardInterrupt, SystemExit): raise except: self.error_log('Error in HTTPServer.tick', level=logging.ERROR, traceback=True) if self.interrupt: while self.interrupt is True: # Wait for self.stop() to complete. See _set_interrupt. time.sleep(0.1) if self.interrupt: raise self.interrupt def error_log(self, msg='', level=20, traceback=False): # Override this in subclasses as desired sys.stderr.write(msg + '\n') sys.stderr.flush() if traceback: tblines = traceback_.format_exc() sys.stderr.write(tblines) sys.stderr.flush() def bind(self, family, type, proto=0): """Create (or recreate) the actual socket object.""" self.socket = socket.socket(family, type, proto) prevent_socket_inheritance(self.socket) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if self.nodelay and not isinstance(self.bind_addr, str): self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) if self.ssl_adapter is not None: self.socket = self.ssl_adapter.bind(self.socket) # If listening on the IPV6 any address ('::' = IN6ADDR_ANY), # activate dual-stack. See # https://github.com/cherrypy/cherrypy/issues/871. if (hasattr(socket, 'AF_INET6') and family == socket.AF_INET6 and self.bind_addr[0] in ('::', '::0', '::0.0.0.0')): try: self.socket.setsockopt( socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) except (AttributeError, socket.error): # Apparently, the socket option is not available in # this machine's TCP stack pass self.socket.bind(self.bind_addr) def tick(self): """Accept a new connection and put it on the Queue.""" try: s, addr = self.socket.accept() if self.stats['Enabled']: self.stats['Accepts'] += 1 if not self.ready: return prevent_socket_inheritance(s) if hasattr(s, 'settimeout'): s.settimeout(self.timeout) makefile = CP_makefile ssl_env = {} # if ssl cert and key are set, we try to be a secure HTTP server if self.ssl_adapter is not None: try: s, ssl_env = self.ssl_adapter.wrap(s) except NoSSLError: msg = ('The client sent a plain HTTP request, but ' 'this server only speaks HTTPS on this port.') buf = ['%s 400 Bad Request\r\n' % self.protocol, 'Content-Length: %s\r\n' % len(msg), 'Content-Type: text/plain\r\n\r\n', msg] sock_to_make = s if six.PY3 else s._sock wfile = makefile(sock_to_make, 'wb', DEFAULT_BUFFER_SIZE) try: wfile.write(ntob(''.join(buf))) except socket.error: x = sys.exc_info()[1] if x.args[0] not in socket_errors_to_ignore: raise return if not s: return makefile = self.ssl_adapter.makefile # Re-apply our timeout since we may have a new socket object if hasattr(s, 'settimeout'): s.settimeout(self.timeout) conn = self.ConnectionClass(self, s, makefile) if not isinstance(self.bind_addr, six.string_types): # optional values # Until we do DNS lookups, omit REMOTE_HOST if addr is None: # sometimes this can happen # figure out if AF_INET or AF_INET6. if len(s.getsockname()) == 2: # AF_INET addr = ('0.0.0.0', 0) else: # AF_INET6 addr = ('::', 0) conn.remote_addr = addr[0] conn.remote_port = addr[1] conn.ssl_env = ssl_env try: self.requests.put(conn) except queue.Full: # Just drop the conn. TODO: write 503 back? conn.close() return except socket.timeout: # The only reason for the timeout in start() is so we can # notice keyboard interrupts on Win32, which don't interrupt # accept() by default return except socket.error: x = sys.exc_info()[1] if self.stats['Enabled']: self.stats['Socket Errors'] += 1 if x.args[0] in socket_error_eintr: # I *think* this is right. EINTR should occur when a signal # is received during the accept() call; all docs say retry # the call, and I *think* I'm reading it right that Python # will then go ahead and poll for and handle the signal # elsewhere. See # https://github.com/cherrypy/cherrypy/issues/707. return if x.args[0] in socket_errors_nonblocking: # Just try again. See # https://github.com/cherrypy/cherrypy/issues/479. return if x.args[0] in socket_errors_to_ignore: # Our socket was closed. # See https://github.com/cherrypy/cherrypy/issues/686. return raise def _get_interrupt(self): return self._interrupt def _set_interrupt(self, interrupt): self._interrupt = True self.stop() self._interrupt = interrupt interrupt = property(_get_interrupt, _set_interrupt, doc='Set this to an Exception instance to ' 'interrupt the server.') def stop(self): """Gracefully shutdown a server that is serving forever.""" self.ready = False if self._start_time is not None: self._run_time += (time.time() - self._start_time) self._start_time = None sock = getattr(self, 'socket', None) if sock: if not isinstance(self.bind_addr, six.string_types): # Touch our own socket to make accept() return immediately. try: host, port = sock.getsockname()[:2] except socket.error: x = sys.exc_info()[1] if x.args[0] not in socket_errors_to_ignore: # Changed to use error code and not message # See # https://github.com/cherrypy/cherrypy/issues/860. raise else: # Note that we're explicitly NOT using AI_PASSIVE, # here, because we want an actual IP to touch. # localhost won't work if we've bound to a public IP, # but it will if we bound to '0.0.0.0' (INADDR_ANY). for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM): af, socktype, proto, canonname, sa = res s = None try: s = socket.socket(af, socktype, proto) # See # http://groups.google.com/group/cherrypy-users/ # browse_frm/thread/bbfe5eb39c904fe0 s.settimeout(1.0) s.connect((host, port)) s.close() except socket.error: if s: s.close() if hasattr(sock, 'close'): sock.close() self.socket = None self.requests.stop(self.shutdown_timeout) class Gateway(object): """A base class to interface HTTPServer with other systems, such as WSGI. """ def __init__(self, req): self.req = req def respond(self): """Process the current request. Must be overridden in a subclass.""" raise NotImplemented # These may either be wsgiserver.SSLAdapter subclasses or the string names # of such classes (in which case they will be lazily loaded). ssl_adapters = { 'builtin': 'cherrypy.wsgiserver.ssl_builtin.BuiltinSSLAdapter', 'pyopenssl': 'cherrypy.wsgiserver.ssl_pyopenssl.pyOpenSSLAdapter', } def get_ssl_adapter_class(name='builtin'): """Return an SSL adapter class for the given name.""" adapter = ssl_adapters[name.lower()] if isinstance(adapter, six.string_types): last_dot = adapter.rfind('.') attr_name = adapter[last_dot + 1:] mod_path = adapter[:last_dot] try: mod = sys.modules[mod_path] if mod is None: raise KeyError() except KeyError: # The last [''] is important. mod = __import__(mod_path, globals(), locals(), ['']) # Let an AttributeError propagate outward. try: adapter = getattr(mod, attr_name) except AttributeError: raise AttributeError("'%s' object has no attribute '%s'" % (mod_path, attr_name)) return adapter # ------------------------------- WSGI Stuff -------------------------------- # class CherryPyWSGIServer(HTTPServer): """A subclass of HTTPServer which calls a WSGI application.""" wsgi_version = (1, 0) """The version of WSGI to produce.""" def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None, max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5, accepted_queue_size=-1, accepted_queue_timeout=10): self.requests = ThreadPool(self, min=numthreads or 1, max=max, accepted_queue_size=accepted_queue_size, accepted_queue_timeout=accepted_queue_timeout) self.wsgi_app = wsgi_app self.gateway = wsgi_gateways[self.wsgi_version] self.bind_addr = bind_addr if not server_name: server_name = socket.gethostname() self.server_name = server_name self.request_queue_size = request_queue_size self.timeout = timeout self.shutdown_timeout = shutdown_timeout self.clear_stats() def _get_numthreads(self): return self.requests.min def _set_numthreads(self, value): self.requests.min = value numthreads = property(_get_numthreads, _set_numthreads) class WSGIGateway(Gateway): """A base class to interface HTTPServer with WSGI.""" def __init__(self, req): self.req = req self.started_response = False self.env = self.get_environ() self.remaining_bytes_out = None def get_environ(self): """Return a new environ dict targeting the given wsgi.version""" raise NotImplemented def respond(self): """Process the current request.""" """ From PEP 333: The start_response callable must not actually transmit the response headers. Instead, it must store them for the server or gateway to transmit only after the first iteration of the application return value that yields a NON-EMPTY string, or upon the application's first invocation of the write() callable. """ response = self.req.server.wsgi_app(self.env, self.start_response) try: for chunk in filter(None, response): if not isinstance(chunk, six.binary_type): raise ValueError('WSGI Applications must yield bytes') self.write(chunk) finally: if hasattr(response, 'close'): response.close() def start_response(self, status, headers, exc_info=None): """ WSGI callable to begin the HTTP response. """ # "The application may call start_response more than once, # if and only if the exc_info argument is provided." if self.started_response and not exc_info: raise AssertionError('WSGI start_response called a second ' 'time with no exc_info.') self.started_response = True # "if exc_info is provided, and the HTTP headers have already been # sent, start_response must raise an error, and should raise the # exc_info tuple." if self.req.sent_headers: try: six.reraise(*exc_info) finally: exc_info = None self.req.status = self._encode_status(status) for k, v in headers: if not isinstance(k, str): raise TypeError( 'WSGI response header key %r is not of type str.' % k) if not isinstance(v, str): raise TypeError( 'WSGI response header value %r is not of type str.' % v) if k.lower() == 'content-length': self.remaining_bytes_out = int(v) out_header = ntob(k), ntob(v) self.req.outheaders.append(out_header) return self.write @staticmethod def _encode_status(status): """ According to PEP 3333, when using Python 3, the response status and headers must be bytes masquerading as unicode; that is, they must be of type "str" but are restricted to code points in the "latin-1" set. """ if six.PY2: return status if not isinstance(status, str): raise TypeError('WSGI response status is not of type str.') return status.encode('ISO-8859-1') def write(self, chunk): """WSGI callable to write unbuffered data to the client. This method is also used internally by start_response (to write data from the iterable returned by the WSGI application). """ if not self.started_response: raise AssertionError('WSGI write called before start_response.') chunklen = len(chunk) rbo = self.remaining_bytes_out if rbo is not None and chunklen > rbo: if not self.req.sent_headers: # Whew. We can send a 500 to the client. self.req.simple_response( '500 Internal Server Error', 'The requested resource returned more bytes than the ' 'declared Content-Length.') else: # Dang. We have probably already sent data. Truncate the chunk # to fit (so the client doesn't hang) and raise an error later. chunk = chunk[:rbo] if not self.req.sent_headers: self.req.sent_headers = True self.req.send_headers() self.req.write(chunk) if rbo is not None: rbo -= chunklen if rbo < 0: raise ValueError( 'Response body exceeds the declared Content-Length.') class WSGIGateway_10(WSGIGateway): """A Gateway class to interface HTTPServer with WSGI 1.0.x.""" def get_environ(self): """Return a new environ dict targeting the given wsgi.version""" req = self.req env = { # set a non-standard environ entry so the WSGI app can know what # the *real* server protocol is (and what features to support). # See http://www.faqs.org/rfcs/rfc2145.html. 'ACTUAL_SERVER_PROTOCOL': req.server.protocol, 'PATH_INFO': bton(req.path), 'QUERY_STRING': bton(req.qs), 'REMOTE_ADDR': req.conn.remote_addr or '', 'REMOTE_PORT': str(req.conn.remote_port or ''), 'REQUEST_METHOD': bton(req.method), 'REQUEST_URI': bton(req.uri), 'SCRIPT_NAME': '', 'SERVER_NAME': req.server.server_name, # Bah. "SERVER_PROTOCOL" is actually the REQUEST protocol. 'SERVER_PROTOCOL': bton(req.request_protocol), 'SERVER_SOFTWARE': req.server.software, 'wsgi.errors': sys.stderr, 'wsgi.input': req.rfile, 'wsgi.multiprocess': False, 'wsgi.multithread': True, 'wsgi.run_once': False, 'wsgi.url_scheme': bton(req.scheme), 'wsgi.version': (1, 0), } if isinstance(req.server.bind_addr, six.string_types): # AF_UNIX. This isn't really allowed by WSGI, which doesn't # address unix domain sockets. But it's better than nothing. env['SERVER_PORT'] = '' else: env['SERVER_PORT'] = str(req.server.bind_addr[1]) # Request headers env.update( ('HTTP_' + bton(k).upper().replace('-', '_'), bton(v)) for k, v in req.inheaders.items() ) # CONTENT_TYPE/CONTENT_LENGTH ct = env.pop('HTTP_CONTENT_TYPE', None) if ct is not None: env['CONTENT_TYPE'] = ct cl = env.pop('HTTP_CONTENT_LENGTH', None) if cl is not None: env['CONTENT_LENGTH'] = cl if req.conn.ssl_env: env.update(req.conn.ssl_env) return env class WSGIGateway_u0(WSGIGateway_10): """A Gateway class to interface HTTPServer with WSGI u.0. WSGI u.0 is an experimental protocol, which uses unicode for keys and values in both Python 2 and Python 3. """ def get_environ(self): """Return a new environ dict targeting the given wsgi.version""" req = self.req env_10 = WSGIGateway_10.get_environ(self) env = dict(map(self._decode_key, env_10.items())) env[six.u('wsgi.version')] = ('u', 0) # Request-URI enc = env.setdefault(six.u('wsgi.url_encoding'), six.u('utf-8')) try: env['PATH_INFO'] = req.path.decode(enc) env['QUERY_STRING'] = req.qs.decode(enc) except UnicodeDecodeError: # Fall back to latin 1 so apps can transcode if needed. env['wsgi.url_encoding'] = 'ISO-8859-1' env['PATH_INFO'] = env_10['PATH_INFO'] env['QUERY_STRING'] = env_10['QUERY_STRING'] env.update(map(self._decode_value, env.items())) return env @staticmethod def _decode_key(item): k, v = item if six.PY2: k = k.decode('ISO-8859-1') return k, v @staticmethod def _decode_value(item): k, v = item skip_keys = 'REQUEST_URI', 'wsgi.input' if six.PY3 or not isinstance(v, bytes) or k in skip_keys: return k, v return k, v.decode('ISO-8859-1') wsgi_gateways = { (1, 0): WSGIGateway_10, ('u', 0): WSGIGateway_u0, } class WSGIPathInfoDispatcher(object): """A WSGI dispatcher for dispatch based on the PATH_INFO. apps: a dict or list of (path_prefix, app) pairs. """ def __init__(self, apps): try: apps = list(apps.items()) except AttributeError: pass # Sort the apps by len(path), descending by_path_len = lambda app: len(app[0]) apps.sort(key=by_path_len, reverse=True) # The path_prefix strings must start, but not end, with a slash. # Use "" instead of "/". self.apps = [(p.rstrip('/'), a) for p, a in apps] def __call__(self, environ, start_response): path = environ['PATH_INFO'] or '/' for p, app in self.apps: # The apps list should be sorted by length, descending. if path.startswith(p + '/') or path == p: environ = environ.copy() environ['SCRIPT_NAME'] = environ['SCRIPT_NAME'] + p environ['PATH_INFO'] = path[len(p):] return app(environ, start_response) start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', '0')]) return [''] SABnzbd-2.3.2/email/badfetch-da.tmpl0000644000000000000000000000072713217005256015245 0ustar 00000000000000#encoding UTF-8 ## ## Dårlig URL Fetch E-mail skabelon for SABnzbd ## Dette er en Cheetah skabelon ## Dokumentation: http://sabnzbd.wikidot.com/email-templates ## ## Linjeskift og blanktegn er betydelig! ## ## Dette er email headers To: $to From: $from Date: $date Subject: SABnzbd kunne ikke hente en NZB X-priority: 5 X-MS-priority: 5 ## Efter dette kommer body, den tomme linje kræves! Hej, SABnzbd kunne ikke hente NZB fra $url. Fejl meddelelsen er: $msg Farvel SABnzbd-2.3.2/email/badfetch-de.tmpl0000644000000000000000000000104413217005256015242 0ustar 00000000000000#encoding UTF-8 ## Translation by Thomas Lucke (Lucky) ## ## Bad URL Fetch Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd konnte eine NZB-Datei nicht herunterladen X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hallo, SABnzbd konnte die NZB-Datei von $url nicht herrunterladen. Die Fehlermeldung war: $msg SABnzbd-2.3.2/email/badfetch-en.tmpl0000644000000000000000000000072213217005256015256 0ustar 00000000000000## ## Bad URL Fetch Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd failed to fetch an NZB X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hi, SABnzbd has failed to retrieve the NZB from $url. The error message was: $msg Bye SABnzbd-2.3.2/email/badfetch-es.tmpl0000644000000000000000000000104513217005256015262 0ustar 00000000000000#encoding UTF-8 ## ## Plantilla de correo para URLs incorrectas de SABnzbd ## Esta es una plantilla Cheetah ## Documentación: http://sabnzbd.wikidot.com/email-templates ## ## Líneas nuevas y espacios en blanco IMPORTAN! ## ## Estas son las cabeceras del email To: $to From: $from Date: $date Subject: SABnzbd ha encontrado un error al recuperar un NZB X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hola, SABnzbd ha encontrado un error al descargar un NZB desde $url. El error ha sido: $msg Un saludo SABnzbd-2.3.2/email/badfetch-fi.tmpl0000644000000000000000000000103013217005256015243 0ustar 00000000000000#encoding UTF-8 ## ## Virheellisen URL-noudon sähköpostin pohja SABnzbd ohjelmalle ## Tämä on Cheetah pohja ## Dokumentaatio: http://sabnzbd.wikidot.com/email-templates ## ## Rivinvaihdot ja välilyönnit ovat merkitseviä! ## ## Tässä on sähköpostin otsikkotiedot To: $to From: $from Date: $date Subject: SABnzbd ei voinut hakea NZB tiedostoa X-priority: 5 X-MS-priority: 5 ## Tämän jälkeen tulee viestin sisältö, tyhjä rivi on pakollinen! Hei, SABnzbd ei voinut hakea NZB tiedostoa osoitteesta $url. Virheviesti: $msg SABnzbd-2.3.2/email/badfetch-fr.tmpl0000644000000000000000000000074213217005256015265 0ustar 00000000000000#encoding UTF-8 ## ## Bad URL Fetch Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd failed to fetch an NZB X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hi, SABnzbd has failed to retrieve the NZB from $url. The error message was: $msg Bye SABnzbd-2.3.2/email/badfetch-he.tmpl0000644000000000000000000000106013217005256015244 0ustar 00000000000000#encoding UTF-8 ## ## SABnzbd רעה עבור URL תבנית דוא"ל של משיכת ## זאת תבנית ברדלס ## http://sabnzbd.wikidot.com/email-templates :תיעוד ## ## !שורות חדשות ורווחים לבנים הם משמעותיים ## ## אלו כותרות הדוא"ל $to :אל $from :מאת תאריך: $date NZB נכשל במשיכת SABnzbd :נושא ## !אחרי זה בא הגוף, השורה הריקה דרושה ,היי .$url מתוך NZB-נכשל לאחזר את ה SABnzbd הודעת השגיאה הייתה: $msg ביי SABnzbd-2.3.2/email/badfetch-nb.tmpl0000644000000000000000000000075113217005256015255 0ustar 00000000000000#encoding UTF-8 ## ## Bad URL Fetch Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd ikke klarte å hente en NZB fil X-priority: 5 X-MS-priority: 5 ## Etter dette kommer meldingen, den tomme linjen er nødvendig! Hei, SABnzbd klarte ikke å hente NZB fra $url. Feilmeldingen var: $msg Hade SABnzbd-2.3.2/email/badfetch-nl.tmpl0000644000000000000000000000100313217005256015256 0ustar 00000000000000#encoding UTF-8 ## ## Ongeldige URL Ophaal Email sjabloon voor SABnzbd ## Dit is een Cheetah sjabloon ## Documentatie: http://sabnzbd.wikidot.com/email-templates ## ## Lege regels en spaties zijn belangrijk! ## ## Dit zijn de email koppen To: $to From: $from Date: $date Subject: Ophalen van NZB door SABnzbd is mislukt X-priority: 5 X-MS-priority: 5 ## Hierna komt het bericht, de lege regel is noodzakelijk! Hi, Het is SABnzbd niet gelukt om een NZB bestand op te halen van $url. De foutmelding was $msg Sorry SABnzbd-2.3.2/email/badfetch-pl.tmpl0000644000000000000000000000102413217005256015263 0ustar 00000000000000#encoding UTF-8 ## ## Szablon wiadomości błędnego pobierania URL SABnzbd ## To jest szablon Cheetah ## Dokumentacja: http://sabnzbd.wikidot.com/email-templates ## ## Znaki nowego wiersza i białe znaki mają znaczenie! ## ## To są nagłówki wiadomości To: $to From: $from Date: $date Subject: SABnzbd nie udało się pobrać pliku NZB X-priority: 5 X-MS-priority: 5 ## Po tym następuje treść. Pusty wiersz jest wymagany! Cześć, SABnzbd nie udało się pobrać pliku NZB z $url. Komunikat błędu: $msg Do usłyszenia. SABnzbd-2.3.2/email/badfetch-pt_BR.tmpl0000644000000000000000000000101313217005256015654 0ustar 00000000000000#encoding UTF-8 ## ## Template de e-mail de busca em URL ruim para SABnzbd ## Este é um template Cheetah ## Documentação: http://sabnzbd.wikidot.com/email-templates ## ## Novas linhas e espaços em branco são significativos! ## ## Estes são os cabeçalhos de e-mail To: $to From: $from Date: $date Subject: SABnzbd falhou ao buscar um NZB X-priority: 5 X-MS-priority: 5 ## Depois daqui vem o corpo. A linha vazia é necessária! Olá, SABnzbd não conseguiu obter o NZB de $url. A mensagem de erro foi: $msg Tchau! SABnzbd-2.3.2/email/badfetch-ro.tmpl0000644000000000000000000000104513217005256015273 0ustar 00000000000000#encoding UTF-8 ## ## Adresă URL Greşită şablon Email pentru SABnybd ## Acesta este un şablon Cheetah ## Documentaţie : http://sabnzbd.wikidot.com/email-templates ## ## Liniile noi şi spaţiile sunt importante! ## ## Acestea sunt headerele email Către: $to De la: $from Dată: $date Subiect: SABnzbd nu a reuşit să descarce un NZB X-priority: 5 X-MS-priority: 5 ## După aceasta urmează corpul email, linia goală e necesară ! Salut, SABnzbd nu a putut descărca NZB-ul de la adresa $url. Mesajul de eroare a fost: $msg La revedere! SABnzbd-2.3.2/email/badfetch-ru.tmpl0000644000000000000000000000150613217005256015303 0ustar 00000000000000#encoding UTF-8 ## ## Шаблон электронной почты для излечения неверного URL-адреса ## Это шаблон Cheetah ## Документация: http://sabnzbd.wikidot.com/email-templates ## ## Новые строки и пробелы имеют значение! ## ## Это заголовки электронной почты To: $to From: $from Date: $date Subject: Службе SABnzbd не удалось загрузить NZB-файл X-priority: 5 X-MS-priority: 5 ## Теперь следует тело сообщения. Пустая строка является обязательной! Привет. Службе SABnzbd не удалось загрузить NZB-файл по адресу $url. Сообщение об ошибке: $msg Конец сообщения SABnzbd-2.3.2/email/badfetch-sr.tmpl0000644000000000000000000000133013217005256015274 0ustar 00000000000000#encoding UTF-8 ## ## Шаблон ел. поште лошег набављања адресе за САБнзбд ## Ово је Гепард шаблон ## Документација: http://sabnzbd.wikidot.com/email-templates ## ## Нови редови и размаци су важни! ## ## Ово су заглавља ел. поште To: $to From: $from Date: $date Subject: САБнзбд није успео да преузме НЗБ X-priority: 5 X-MS-priority: 5 ## После тога долази разрада, празни редови су потребни! Здраво, САБнзбд није успео да преузме НЗБ са „$url“. Порука грешке је: $msg Поздрав SABnzbd-2.3.2/email/badfetch-sv.tmpl0000644000000000000000000000100313217005256015275 0ustar 00000000000000#encoding UTF-8 ## ## Bad URL Fetch Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd misslyckades med att hämta en NZB -fil X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hej, SABnzbd har misslyckats med att hämta NZB -filen från $url. Felmeddelandet lyder: $msg Hej då SABnzbd-2.3.2/email/badfetch-zh_CN.tmpl0000644000000000000000000000066113217005256015657 0ustar 00000000000000#encoding UTF-8 ## ## SABnzbd 装取 URL 错误电子邮件模板 ## 这是一款 Cheetah 模板 ## 文档: http://sabnzbd.wikidot.com/email-templates ## ## 新行与空格均有重要意义! ## ## 这些是电子邮件头 To: $to From: $from Date: $date Subject: SABnzbd 装取 NZB 失败 X-priority: 5 X-MS-priority: 5 ## 到主体部分时必须要有空行! Hi, SABnzbd 从 $url 检索 NZB 失败。 错误信息为: $msg Bye SABnzbd-2.3.2/email/email-da.tmpl0000644000000000000000000000205113217005256014564 0ustar 00000000000000#encoding UTF-8 ## ## Standard Email skabelon til SABnzbd ## Dette er en Cheetah skabelon ## Dokumentation: http://sabnzbd.wikidot.com/email-templates ## ## Linjeskift og blanktegn er betydelig! ## ## Disse er e-mail-headerne To: $to From: $from Date: $date Subject: SABnzbd har job $name X-priority: 5 X-MS-priority: 5 ## Efter dette kommer body, den tomme linje kræves! Hej, SABnzbd har hentet "$name" SABnzbd kunne ikke hente "$name" Færdig kl. $end_time Hentet $size Resultat af job: Etape $stage $result Output fra bruger script "$script" (Exit code = $script_ret): $script_output Enjoy! Sorry! SABnzbd-2.3.2/email/email-de.tmpl0000644000000000000000000000232613217005256014575 0ustar 00000000000000#encoding UTF-8 ## Translation by Severin Heiniger ## ## Default Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd Auftrag $name X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hi, SABnzbd hat "$name" heruntergeladen SABnzbd konnte "$name" nicht herunterladen Fertiggestellt: $end_time Heruntergeladen: $size Ergebnis des Auftrages: Stufe $stage $result Ausgabe des Benutzerskripts "$script" (beendet mit Code $script_ret): $script_output Viel Spass! Entschuldigung! SABnzbd-2.3.2/email/email-en.tmpl0000644000000000000000000000205713217005256014610 0ustar 00000000000000## ## Default Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd has job $name X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hi, SABnzbd has downloaded "$name" SABnzbd has failed to download "$name" Finished at $end_time Downloaded $size Results of the job: Stage $stage $result Output from user script "$script" (Exit code = $script_ret): $script_output Enjoy! Sorry! SABnzbd-2.3.2/email/email-es.tmpl0000644000000000000000000000224213217005256014611 0ustar 00000000000000#encoding UTF-8 ## ## Plantilla de correo predeterminada para SABnzbd ## This a Cheetah template ## Documentación: http://sabnzbd.wikidot.com/email-templates ## ## !Los saltos de línea y espacios en blanco son significativos¡ ## ## Cabeceras de correo electrónico To: $to From: $from Date: $date Subject: SABnzbd job $name X-priority: 5 X-MS-priority: 5 ## !Después de esto viene el cuerpo del mensaje, la línea en blanco es necesaria! Hola, SABnzbd he bajado "$name" SABnzbd fallo en bajar "$name" Terminado a las $end_time $size bajado Resultado de la transferencia: Etapa $stage $result Producción desde el script de usuario "$script" (Exit code = $script_ret): $script_output Que lo disfrutes! Perdon! SABnzbd-2.3.2/email/email-fi.tmpl0000644000000000000000000000224113217005256014577 0ustar 00000000000000#encoding UTF-8 ## ## Oletus sähköpostipohja SABnzbd:lle ## Tämä on Cheetah pohja ## Dokumentaatio: http://sabnzbd.wikidot.com/email-templates ## ## Rivinvaihdot ja välilyönnit ovat merkitseviä! ## ## Nämä ovat otsaketiedot. Rivien ensimmäisiä sanoja ei saa vaihtaa! To: $to From: $from Date: $date Subject: SABnzbd on työssä $name X-priority: 5 X-MS-priority: 5 ## Tämän jälkeen tulee viestin runko, ensimmäinen rivinvaihto on pakollinen! Hei, SABnzbd on ladannut "$name" SABnzbd on epäonnistunut "$name" latauksessa Valmistui $end_time Ladattu $size Työn lopputulos: Tila $stage $result Käyttäjän skriptin tuloste "$script" (Exit code = $script_ret): $script_output Nauti! Pahoittelut! SABnzbd-2.3.2/email/email-fr.tmpl0000644000000000000000000000223113217005256014607 0ustar 00000000000000#encoding UTF-8 ## ## Template Email pour SABnzbd ## Ceci est un template Cheetah ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Les retours à la ligne et les espaces sont importants ! ## ## Entêtes de l'email To: $to From: $from Date: $date Subject: SABnzbd SuccèsEchec du téléchargement $name X-priority: 5 X-MS-priority: 5 ## Après cela vient le contenu, la ligne vide est nécessaire! Bonjour, SABnzbd a téléchargé avec succès "$name" SABnzbd a téléchargé sans succès "$name" Terminé à $end_time Téléchargé $size Résultat du téléchargement : Etape $stage $result Sortie du script utilisateur "$script" (Code Retour = $script_ret): $script_output A bientôt ! Désolé ! SABnzbd-2.3.2/email/email-he.tmpl0000644000000000000000000000225613217005256014603 0ustar 00000000000000#encoding UTF-8 ## ## SABnzbd תבנית דוא"ל ברירת מחדל עבור ## זאת תבנית ברדלס ## http://sabnzbd.wikidot.com/email-templates :תיעוד ## ## !שורות חדשות ורווחים לבנים הם משמעותיים ## ## אלו כותרות הדוא"ל $to :אל $from :מאת תאריך: $date $name יש עבודה אשר SABnzbd-נושא: ל ## !אחרי זה בא הגוף, השורה הריקה דרושה ,היי SABnzbd הוריד את "$name" SABnzbd נכשל להוריד את "$name" הסתיים ב-$end_time הורדו $size :תוצאות העבודה שלב $stage $result :(קוד יציאה = $script_ret) "$script" פלט מתסריט משתמש $script_output !תהנה !סליחה SABnzbd-2.3.2/email/email-nb.tmpl0000644000000000000000000000213413217005256014601 0ustar 00000000000000#encoding UTF-8 ## Translation by ProtX ## ## Default Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd har jobb $name X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hei, SABnzbd har lastet ned "$name" SABnzbd mislyktes med å laste ned "$name" Ferdig $end_time Nedlastet $size Resultat av jobben: Steg $stage $result Utskrift fra brukerskript "$script" (Exit code = $script_ret): $script_output Gratulerer! Synd! SABnzbd-2.3.2/email/email-nl.tmpl0000644000000000000000000000216713217005256014621 0ustar 00000000000000#encoding UTF-8 ## ## Standaard Email sjabloon voor SABnzbd ## Dit is een Cheetah sjabloon ## Documentatie: http://sabnzbd.wikidot.com/email-templates ## ## Lege regels en witruimte zijn belangrijk! ## ## Dit zijn de email koppen To: $to From: $from Date: $date Subject: SABnzbd: opdracht $name is X-priority: 5 X-MS-priority: 5 ## Hier onder volgt de hoofdtekst, de lege regel is noodzakelijk! Hallo, SABnzbd heeft "$name" gedownload SABnzbd is niet geslaagd in het downloaden van "$name" Klaar om $end_time Hoeveelheid gedownload $size Resultaat van de opdracht: Fase $stage $result Bericht van het script "$script" (Exit code = $script_ret): $script_output Veel plezier! Sorry! SABnzbd-2.3.2/email/email-pl.tmpl0000644000000000000000000000210513217005256014613 0ustar 00000000000000#encoding UTF-8 ## ## Domyślny szablon maila w SABnzbd ## To jest szablon Cheetah ## Dokumentacja: http://sabnzbd.wikidot.com/email-templates ## ## Znak nowego wiersza i spacji ma znaczenie! ## ## To są nagłowki maila To: $to From: $from Date: $date Subject: SABnzbd zadanie $name X-priority: 5 X-MS-priority: 5 ## Następnie treść maila, wymagana jest pusta linia! Cześć, SABnzbd pobrał "$name" SABnzbd nie pobrał "$name" Zakończono o $end_time Pobrano $size Rezultat zadania: Etap $stage $result Odpowiedź od skryptu "$script" (kod wyjścia = $script_ret): $script_output Baw się dobrze! Przykro mi! SABnzbd-2.3.2/email/email-pt_BR.tmpl0000644000000000000000000000216313217005256015212 0ustar 00000000000000#encoding UTF-8 ## ## Template padrão de e-mail para SABnzbd ## Este é um template Cheetah ## Documentação: http://sabnzbd.wikidot.com/email-templates ## ## Novas linhas e espaços em branco são significativos! ## ## Estes são os cabeçalhos de e-mail To: $to From: $from Date: $date Subject: SABnzbd a tarefa $name X-priority: 5 X-MS-priority: 5 ## Depois daqui vem o corpo. A linha vazia é necessária! Olá, SABnzbd baixou "$name" SABnzbd falhou no download de "$name" Completado em $end_time Baixados $size Resultados da tarefa: Etapa $stage $result Retorno do script de usuário "$script" (Código de retorno = $script_ret): $script_output Aproveite! Lamento! SABnzbd-2.3.2/email/email-ro.tmpl0000644000000000000000000000220713217005256014623 0ustar 00000000000000#encoding UTF-8 ## ## Șablon Email Original pentru SABnzbd ## Acesta este un Șablon Cheetah ## Documentație: http://sabnzbd.wikidot.com/email-templates ## ##Rândurile noi și caracterele spațiu sunt importante! ## ## Acestea sunt antetele email To: $to From: $from Date: $date Subject: SABnzbd sarcina $name X-priority: 5 X-MS-priority: 5 ## După acesta urmează conţinutul, este necesar o linie goală! Salut, SABnzbd a descărcat "$name" SABnzbd nu a reuşit să descarce "$name" Terminat la $end_time Mărime $size Rezultatele sarcinii: Stagiu $stage $result Rezultatul script-ului utilizatorului "$script" (Exit code = $script_ret): $script_output Bucuraţi-vă! Ne pare rau! SABnzbd-2.3.2/email/email-ru.tmpl0000644000000000000000000000303413217005256014630 0ustar 00000000000000#encoding UTF-8 ## ## Стандартный шаблон сообщения электронной почты ## Это шаблон Cheetah ## Документация: http://sabnzbd.wikidot.com/email-templates ## ## Новые строки и пробелы имеют значение! ## ## Это заголовки электронной почты To: $to From: $from Date: $date Subject: SABnzbd: задание $name X-priority: 5 X-MS-priority: 5 ## Теперь следует тело сообщения. Пустая строка является обязательной! Привет. Системой SABnzbd загружено задание «$name» Системе SABnzbd не удалось загрузить «$name» Время окончания загрузки: $end_time Загруженный размер: $size Результаты задания: Stage $stage $result Результат выполнения сценария «$script» (Exit code = $script_ret): $script_output Удачи! Сожалеем. SABnzbd-2.3.2/email/email-sr.tmpl0000644000000000000000000000256313217005256014634 0ustar 00000000000000#encoding UTF-8 ## ## Основни шаблон ел. поште за САБнзбд ## Ово је Гепард шаблон ## Документација: http://sabnzbd.wikidot.com/email-templates ## ## Нови редови и размаци су важни! ## ## Ово су заглавља ел. поште To: $to From: $from Date: $date Subject: САБнзбд је посао „$name“ X-priority: 5 X-MS-priority: 5 ## После тога долази разрада, празни редови су потребни! Здраво, САБнзбд је преузео „$name“ САБнзбд није успео да преузме „$name“ Завршено је у $end_time Преузето је $size \n Резултат рада: Фаза $stage $result Излаз корисничке скрипте „$script“ (Шифра излаза = $script_ret): $script_output Уживајте! Жао ми је! SABnzbd-2.3.2/email/email-sv.tmpl0000644000000000000000000000220013217005256014624 0ustar 00000000000000#encoding UTF-8 ## Translation by Andreas Lindberg andypandyswe@gmail.com ## Default Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd has job $name X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hej, SABnzbd har laddat ned "$name" SABnzbd misslyckades med att ladda ned "$name" Färdig $end_time Nedladdat $size Resultat: Stage $stage $result Utmatning från användarskript "$script" (Exit code = $script_ret): $script_output Lycka till! Beklagar! SABnzbd-2.3.2/email/email-zh_CN.tmpl0000644000000000000000000000204013217005256015177 0ustar 00000000000000#encoding UTF-8 ## ## SABnzbd 默认电子邮件模板 ## 这是一款 Cheetah 模板 ## 文档: http://sabnzbd.wikidot.com/email-templates ## ## 新行与空格均有重要意义! ## ## 这些是电子邮件头 To: $to From: $from Date: $date Subject: SABnzbd 已任务 $name X-priority: 5 X-MS-priority: 5 ## 到主体部分时,必须要有空行! Hi, SABnzbd 已完成 "$name" 的下载 SABnzbd 下载 "$name" 失败 完成于 $end_time 已下载 $size 任务结果: Stage $stage $result 用户脚本 "$script" 输出内容 (退出代码 = $script_ret): $script_output Enjoy! 非常抱歉! SABnzbd-2.3.2/email/rss-da.tmpl0000644000000000000000000000103713217005256014307 0ustar 00000000000000#encoding UTF-8 ## ## RSS Email skabelon til SABnzbd ## Dette er Cheetah skabelon ## Dokumentation: http://sabnzbd.wikidot.com/email-templates ## ## Linjeskift og blanktegn er betydelig! ## ## Dette er email headers To: $to From: $from Date: $date Subject: SABnzbd har tilføjet $antal jobs til køen X-priority: 5 X-MS-priority: 5 ## Efter dette kommer body, den tomme linje kræves! Hej, SABnzbd har tilføjet $antal job(s) til køen. De er fra RSS feed "$feed". $job Farvel SABnzbd-2.3.2/email/rss-de.tmpl0000644000000000000000000000111213217005256014305 0ustar 00000000000000#encoding UTF-8 ## ## RSS Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd hat $amount Aufträge zur Warteschlange hinzugefügt X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hallo, SABnzbd hat $amount Aufträge zur Warteschlange hinzugefügt. Sie stammen vom RSS-Feed "$feed". $job SABnzbd-2.3.2/email/rss-en.tmpl0000644000000000000000000000103213217005256014320 0ustar 00000000000000## ## RSS Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd has added $amount jobs to the queue X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hi, SABnzbd has added $amount job(s) to the queue. They are from RSS feed "$feed". $job Bye SABnzbd-2.3.2/email/rss-es.tmpl0000644000000000000000000000117413217005256014334 0ustar 00000000000000#encoding UTF-8 ## ## Plantilla de correo RSS para SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## !Los saltos de línea y espacios en blanco son significativos¡ ## ## Cabeceras de correo electrónico To: $to From: $from Date: $date Subject: SABnzbd he añadido $amount transferencia(s) a la cola X-priority: 5 X-MS-priority: 5 ## !Después de esto viene el cuerpo del mensaje, la línea en blanco es necesaria! Hola, SABnzbd he añadido $amount transferencia(s) a la cola. Originaron desde el RSS "$feed". $job Adios SABnzbd-2.3.2/email/rss-fi.tmpl0000644000000000000000000000117213217005256014321 0ustar 00000000000000#encoding UTF-8 ## ## RSS sähköpostipohja SABnzbd:lle ## Tämä on Cheetah pohja ## Dokumentaatio: http://sabnzbd.wikidot.com/email-templates ## ## Rivinvaihdot ja välilyönnit ovat merkitseviä! ## ## Nämä ovat otsaketiedot. Rivien ensimmäisiä sanoja ei saa vaihtaa! To: $to From: $from Date: $date Subject: SABnzbd on lisännyt $amount työtä jonoon X-priority: 5 X-MS-priority: 5 ## Tämän jälkeen tulee viestin runko, ensimmäinen rivinvaihto on pakollinen! Hei, SABnzbd on lisännyt $amount työtä jonoon. Ne ovat RSS syötteestä "$feed". $job Heippa SABnzbd-2.3.2/email/rss-fr.tmpl0000644000000000000000000000114613217005256014333 0ustar 00000000000000#encoding UTF-8 ## ## Template Email pour SABnzbd ## Ceci est un template Cheetah ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Les retours à la ligne et les espaces sont importants ! ## ## Entêtes de l'email To: $to From: $from Date: $date Subject: SABnzbd a ajouté $amount fichier(s) à la file d'attente X-priority: 5 X-MS-priority: 5 ## Après cela vient le contenu, la ligne vide est nécessaire! Bonjour, SABnzbd a ajouté $amount fichier(s) à la file d'attente. Ils proviennent du Flux RSS "$feed". $job Au Revoir SABnzbd-2.3.2/email/rss-he.tmpl0000644000000000000000000000114213217005256014314 0ustar 00000000000000#encoding UTF-8 ## ## SABnzbd עבור RSS תבנית דוא"ל ## זאת תבנית ברדלס ## http://sabnzbd.wikidot.com/email-templates :תיעוד ## ## !שורות חדשות ורווחים לבנים הם משמעותיים ## ## אלו כותרות הדוא"ל $to :אל $from :מאת תאריך: $date הוסיף $amount עבודות לתור SABnzbd :נושא ## !אחרי זה בא הגוף, השורה הריקה דרושה ,היי .הוסיף $amount עבודות לתור SABnzbd ."$feed" בשם RSS הם מהזנת $job ביי SABnzbd-2.3.2/email/rss-nb.tmpl0000644000000000000000000000106013217005256014316 0ustar 00000000000000#encoding UTF-8 ## ## RSS Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd har lagt $amount jobber til køen X-priority: 5 X-MS-priority: 5 ## Etter dette kommer meldingen, den tomme linjen er nødvendig! Hei, SABnzbd har lagt $amount jobb(er) til køen. Disse er fra RSS feeden "$feed". $job Hade SABnzbd-2.3.2/email/rss-nl.tmpl0000644000000000000000000000110313217005256014326 0ustar 00000000000000#encoding UTF-8 ## ## RSS Email sjabloon voor SABnzbd ## Dit is een Cheetah sjabloon ## Documentatie: http://sabnzbd.wikidot.com/email-templates ## ## Lege regels en spaties zijn belangrijk! ## ## Dit zijn de email koppen To: $to From: $from Date: $date Subject: SABnzbd heeft $amount opdrachten aan de wachtrij toegevoegd X-priority: 5 X-MS-priority: 5 ## Hierna komt de inhoud, de lege regel is benodigd! Hallo, SABnzbd heeft $amount opdrachten aan de wachtrij toegevoegd. Ze komen van de RSS bron "$feed". $job SABnzbd-2.3.2/email/rss-pl.tmpl0000644000000000000000000000107413217005256014337 0ustar 00000000000000#encoding UTF-8 ## ## Szablon wiadomości RSS dla SABnzbd ## To jest szablon Cheetah ## Dokumentacja: http://sabnzbd.wikidot.com/email-templates ## ## Znak nowego wiersza i spacji ma znaczenie! ## ## To są nagłowki maila To: $to From: $from Date: $date Subject: SABnzbd dodał $amount zadań/zadania do kolejki X-priority: 5 X-MS-priority: 5 ## Następnie treść maila, wymagana jest pusta linia! Cześć, SABnzbd dodał $amount zadanie/zadań do kolejki. Pochodzą one z wiadomości RSS "$feed". $job Nara SABnzbd-2.3.2/email/rss-pt_BR.tmpl0000644000000000000000000000125313217005256014731 0ustar 00000000000000#encoding UTF-8 ## ## Template de e-mail RSS para SABnzbd ## Este é um template Cheetah ## Documentação: http://sabnzbd.wikidot.com/email-templates ## ## Novas linhas e espaços em branco são significativos! ## ## Estes são os cabeçalhos de e-mail To: $to From: $from Date: $date Subject: SABnzbd adicionou $amount à fila X-priority: 5 X-MS-priority: 5 ## Depois daqui vem o corpo. A linha vazia é necessária! Olá, SABnzbd adicionou $amount à fila. Elas são do feed RSS "$feed". $job Tchau! SABnzbd-2.3.2/email/rss-ro.tmpl0000644000000000000000000000113613217005256014343 0ustar 00000000000000#encoding UTF-8 ## Şablon Email RSS pentru SABnzbd ## Acesta este un şablon Cheetah ## Documentaţie: http://sabnzbd.wikidot.com/email-templates ## ## Rândurile noi și caracterele spațiu sunt importante! ## ## Acestea sunt antetele email To: $to From: $from Date: $date Subject: SABnzbd a adăugat $amount sarcini în coadă X-priority: 5 X-MS-priority: 5 ## După acesta urmează conţinutul, este necesar o linie goală! Salut, SABnzbd a adăugat $amount sarcină(e) în coadă. Ele sunt din fluxuri RSS "$feed". $job La revedere ! SABnzbd-2.3.2/email/rss-ru.tmpl0000644000000000000000000000156113217005256014353 0ustar 00000000000000#encoding UTF-8 ## ## Шаблон RSS для электронной почты ## Это шаблон Cheetah ## Документация: http://sabnzbd.wikidot.com/email-templates ## ## Новые строки и пробелы имеют значение! ## ## Это заголовки электронной почты To: $to From: $from Date: $date Subject: В очередь загрузки SABnzbd добавлены задания: $amount X-priority: 5 X-MS-priority: 5 ## Теперь следует тело сообщения. Пустая строка является обязательной! Привет. В очередь загрузки SABnzbd были добавлены задания: $amount. Они были получены из RSS-ленты «$feed». $job До свидания SABnzbd-2.3.2/email/rss-sr.tmpl0000644000000000000000000000136713217005256014355 0ustar 00000000000000#encoding UTF-8 ## ## РСС шаблон ел. поште за САБнзбд ## Ово је Гепард шаблон ## Документација: http://sabnzbd.wikidot.com/email-templates ## ## Нови редови и размаци су важни! ## ## Ово су заглавља ел. поште To: $to From: $from Date: $date Subject САБнзбд је додао $amount посла у ред X-priority: 5 X-MS-priority: 5 ## После тога долази разрада, празни редови су потребни! Здраво, САБнзбд је додао $amount посао(ла) у ред. Долазе са РСС довода „$feed“. $job Поздрав SABnzbd-2.3.2/email/rss-sv.tmpl0000644000000000000000000000105313217005256014351 0ustar 00000000000000#encoding UTF-8 ## ## RSS Email template for SABnzbd ## This a Cheetah template ## Documentation: http://sabnzbd.wikidot.com/email-templates ## ## Newlines and whitespace are significant! ## ## These are the email headers To: $to From: $from Date: $date Subject: SABnzbd har lagt till $amount jobb i kön X-priority: 5 X-MS-priority: 5 ## After this comes the body, the empty line is required! Hej, SABnzbd har lagt till $amount jobb i kön. De kommer från RSS feed "$feed". $job Hej då SABnzbd-2.3.2/email/rss-zh_CN.tmpl0000644000000000000000000000102313217005256014717 0ustar 00000000000000#encoding UTF-8 ## ## SABnzbd RSS 电子邮件模板 ## 这是一款 Cheetah 模板 ## 文档: http://sabnzbd.wikidot.com/email-templates ## ## 新行及空格均有重要意义! ## ## 这些是电子邮件头 To: $to From: $from Date: $date Subject: SABnzbd 已将 $amount 项任务加入队列 X-priority: 5 X-MS-priority: 5 ## 到主体部分时,必须要有空行! Hi, SABnzbd 已将 $amount 项任务加入队列。 它们出自 RSS feed "$feed"。 $job Bye SABnzbd-2.3.2/gntp/cli.py0000644000000000000000000001005513217005257013223 0ustar 00000000000000# Copyright: 2013 Paul Traylor # These sources are released under the terms of the MIT license: see LICENSE import logging import os import sys from optparse import OptionParser, OptionGroup from gntp.notifier import GrowlNotifier from gntp.shim import RawConfigParser from gntp.version import __version__ DEFAULT_CONFIG = os.path.expanduser('~/.gntp') config = RawConfigParser({ 'hostname': 'localhost', 'password': None, 'port': 23053, }) config.read([DEFAULT_CONFIG]) if not config.has_section('gntp'): config.add_section('gntp') class ClientParser(OptionParser): def __init__(self): OptionParser.__init__(self, version="%%prog %s" % __version__) group = OptionGroup(self, "Network Options") group.add_option("-H", "--host", dest="host", default=config.get('gntp', 'hostname'), help="Specify a hostname to which to send a remote notification. [%default]") group.add_option("--port", dest="port", default=config.getint('gntp', 'port'), type="int", help="port to listen on [%default]") group.add_option("-P", "--password", dest='password', default=config.get('gntp', 'password'), help="Network password") self.add_option_group(group) group = OptionGroup(self, "Notification Options") group.add_option("-n", "--name", dest="app", default='Python GNTP Test Client', help="Set the name of the application [%default]") group.add_option("-s", "--sticky", dest='sticky', default=False, action="store_true", help="Make the notification sticky [%default]") group.add_option("--image", dest="icon", default=None, help="Icon for notification (URL or /path/to/file)") group.add_option("-m", "--message", dest="message", default=None, help="Sets the message instead of using stdin") group.add_option("-p", "--priority", dest="priority", default=0, type="int", help="-2 to 2 [%default]") group.add_option("-d", "--identifier", dest="identifier", help="Identifier for coalescing") group.add_option("-t", "--title", dest="title", default=None, help="Set the title of the notification [%default]") group.add_option("-N", "--notification", dest="name", default='Notification', help="Set the notification name [%default]") group.add_option("--callback", dest="callback", help="URL callback") self.add_option_group(group) # Extra Options self.add_option('-v', '--verbose', dest='verbose', default=0, action='count', help="Verbosity levels") def parse_args(self, args=None, values=None): values, args = OptionParser.parse_args(self, args, values) if values.message is None: print('Enter a message followed by Ctrl-D') try: message = sys.stdin.read() except KeyboardInterrupt: exit() else: message = values.message if values.title is None: values.title = ' '.join(args) # If we still have an empty title, use the # first bit of the message as the title if values.title == '': values.title = message[:20] values.verbose = logging.WARNING - values.verbose * 10 return values, message def main(): (options, message) = ClientParser().parse_args() logging.basicConfig(level=options.verbose) if not os.path.exists(DEFAULT_CONFIG): logging.info('No config read found at %s', DEFAULT_CONFIG) growl = GrowlNotifier( applicationName=options.app, notifications=[options.name], defaultNotifications=[options.name], hostname=options.host, password=options.password, port=options.port, ) result = growl.register() if result is not True: exit(result) # This would likely be better placed within the growl notifier # class but until I make _checkIcon smarter this is "easier" if options.icon and growl._checkIcon(options.icon) is False: logging.info('Loading image %s', options.icon) f = open(options.icon, 'rb') options.icon = f.read() f.close() result = growl.notify( noteType=options.name, title=options.title, description=message, icon=options.icon, sticky=options.sticky, priority=options.priority, callback=options.callback, identifier=options.identifier, ) if result is not True: exit(result) if __name__ == "__main__": main() SABnzbd-2.3.2/gntp/config.py0000644000000000000000000000417513217005257013727 0ustar 00000000000000# Copyright: 2013 Paul Traylor # These sources are released under the terms of the MIT license: see LICENSE """ The gntp.config module is provided as an extended GrowlNotifier object that takes advantage of the ConfigParser module to allow us to setup some default values (such as hostname, password, and port) in a more global way to be shared among programs using gntp """ import logging import os import gntp.notifier import gntp.shim __all__ = [ 'mini', 'GrowlNotifier' ] logger = logging.getLogger(__name__) class GrowlNotifier(gntp.notifier.GrowlNotifier): """ ConfigParser enhanced GrowlNotifier object For right now, we are only interested in letting users overide certain values from ~/.gntp :: [gntp] hostname = ? password = ? port = ? """ def __init__(self, *args, **kwargs): config = gntp.shim.RawConfigParser({ 'hostname': kwargs.get('hostname', 'localhost'), 'password': kwargs.get('password'), 'port': kwargs.get('port', 23053), }) config.read([os.path.expanduser('~/.gntp')]) # If the file does not exist, then there will be no gntp section defined # and the config.get() lines below will get confused. Since we are not # saving the config, it should be safe to just add it here so the # code below doesn't complain if not config.has_section('gntp'): logger.info('Error reading ~/.gntp config file') config.add_section('gntp') kwargs['password'] = config.get('gntp', 'password') kwargs['hostname'] = config.get('gntp', 'hostname') kwargs['port'] = config.getint('gntp', 'port') super(GrowlNotifier, self).__init__(*args, **kwargs) def mini(description, **kwargs): """Single notification function Simple notification function in one line. Has only one required parameter and attempts to use reasonable defaults for everything else :param string description: Notification message """ kwargs['notifierFactory'] = GrowlNotifier gntp.notifier.mini(description, **kwargs) if __name__ == '__main__': # If we're running this module directly we're likely running it as a test # so extra debugging is useful logging.basicConfig(level=logging.INFO) mini('Testing mini notification') SABnzbd-2.3.2/gntp/core.py0000644000000000000000000003365613217005257013420 0ustar 00000000000000# Copyright: 2013 Paul Traylor # These sources are released under the terms of the MIT license: see LICENSE import hashlib import re import time import gntp.shim import gntp.errors as errors __all__ = [ 'GNTPRegister', 'GNTPNotice', 'GNTPSubscribe', 'GNTPOK', 'GNTPError', 'parse_gntp', ] #GNTP/ [:][ :.] GNTP_INFO_LINE = re.compile( 'GNTP/(?P\d+\.\d+) (?PREGISTER|NOTIFY|SUBSCRIBE|\-OK|\-ERROR)' + ' (?P[A-Z0-9]+(:(?P[A-F0-9]+))?) ?' + '((?P[A-Z0-9]+):(?P[A-F0-9]+).(?P[A-F0-9]+))?\r\n', re.IGNORECASE ) GNTP_INFO_LINE_SHORT = re.compile( 'GNTP/(?P\d+\.\d+) (?PREGISTER|NOTIFY|SUBSCRIBE|\-OK|\-ERROR)', re.IGNORECASE ) GNTP_HEADER = re.compile('([\w-]+):(.+)') GNTP_EOL = gntp.shim.b('\r\n') GNTP_SEP = gntp.shim.b(': ') class _GNTPBuffer(gntp.shim.StringIO): """GNTP Buffer class""" def writeln(self, value=None): if value: self.write(gntp.shim.b(value)) self.write(GNTP_EOL) def writeheader(self, key, value): if not isinstance(value, str): value = str(value) self.write(gntp.shim.b(key)) self.write(GNTP_SEP) self.write(gntp.shim.b(value)) self.write(GNTP_EOL) class _GNTPBase(object): """Base initilization :param string messagetype: GNTP Message type :param string version: GNTP Protocol version :param string encription: Encryption protocol """ def __init__(self, messagetype=None, version='1.0', encryption=None): self.info = { 'version': version, 'messagetype': messagetype, 'encryptionAlgorithmID': encryption } self.hash_algo = { 'MD5': hashlib.md5, 'SHA1': hashlib.sha1, 'SHA256': hashlib.sha256, 'SHA512': hashlib.sha512, } self.headers = {} self.resources = {} # For Python2 we can just return the bytes as is without worry # but on Python3 we want to make sure we return the packet as # a unicode string so that things like logging won't get confused if gntp.shim.PY2: def __str__(self): return self.encode() else: def __str__(self): return gntp.shim.u(self.encode()) def _parse_info(self, data): """Parse the first line of a GNTP message to get security and other info values :param string data: GNTP Message :return dict: Parsed GNTP Info line """ match = GNTP_INFO_LINE.match(data) if not match: raise errors.ParseError('ERROR_PARSING_INFO_LINE') info = match.groupdict() if info['encryptionAlgorithmID'] == 'NONE': info['encryptionAlgorithmID'] = None return info def set_password(self, password, encryptAlgo='MD5'): """Set a password for a GNTP Message :param string password: Null to clear password :param string encryptAlgo: Supports MD5, SHA1, SHA256, SHA512 """ if not password: self.info['encryptionAlgorithmID'] = None self.info['keyHashAlgorithm'] = None return self.password = gntp.shim.b(password) self.encryptAlgo = encryptAlgo.upper() if not self.encryptAlgo in self.hash_algo: raise errors.UnsupportedError('INVALID HASH "%s"' % self.encryptAlgo) hashfunction = self.hash_algo.get(self.encryptAlgo) password = password.encode('utf8') seed = time.ctime().encode('utf8') salt = hashfunction(seed).hexdigest() saltHash = hashfunction(seed).digest() keyBasis = password + saltHash key = hashfunction(keyBasis).digest() keyHash = hashfunction(key).hexdigest() self.info['keyHashAlgorithmID'] = self.encryptAlgo self.info['keyHash'] = keyHash.upper() self.info['salt'] = salt.upper() def _decode_hex(self, value): """Helper function to decode hex string to `proper` hex string :param string value: Human readable hex string :return string: Hex string """ result = '' for i in range(0, len(value), 2): tmp = int(value[i:i + 2], 16) result += chr(tmp) return result def _decode_binary(self, rawIdentifier, identifier): rawIdentifier += '\r\n\r\n' dataLength = int(identifier['Length']) pointerStart = self.raw.find(rawIdentifier) + len(rawIdentifier) pointerEnd = pointerStart + dataLength data = self.raw[pointerStart:pointerEnd] if not len(data) == dataLength: raise errors.ParseError('INVALID_DATA_LENGTH Expected: %s Recieved %s' % (dataLength, len(data))) return data def _validate_password(self, password): """Validate GNTP Message against stored password""" self.password = password if password is None: raise errors.AuthError('Missing password') keyHash = self.info.get('keyHash', None) if keyHash is None and self.password is None: return True if keyHash is None: raise errors.AuthError('Invalid keyHash') if self.password is None: raise errors.AuthError('Missing password') keyHashAlgorithmID = self.info.get('keyHashAlgorithmID','MD5') password = self.password.encode('utf8') saltHash = self._decode_hex(self.info['salt']) keyBasis = password + saltHash self.key = self.hash_algo[keyHashAlgorithmID](keyBasis).digest() keyHash = self.hash_algo[keyHashAlgorithmID](self.key).hexdigest() if not keyHash.upper() == self.info['keyHash'].upper(): raise errors.AuthError('Invalid Hash') return True def validate(self): """Verify required headers""" for header in self._requiredHeaders: if not self.headers.get(header, False): raise errors.ParseError('Missing Notification Header: ' + header) def _format_info(self): """Generate info line for GNTP Message :return string: """ info = 'GNTP/%s %s' % ( self.info.get('version'), self.info.get('messagetype'), ) if self.info.get('encryptionAlgorithmID', None): info += ' %s:%s' % ( self.info.get('encryptionAlgorithmID'), self.info.get('ivValue'), ) else: info += ' NONE' if self.info.get('keyHashAlgorithmID', None): info += ' %s:%s.%s' % ( self.info.get('keyHashAlgorithmID'), self.info.get('keyHash'), self.info.get('salt') ) return info def _parse_dict(self, data): """Helper function to parse blocks of GNTP headers into a dictionary :param string data: :return dict: Dictionary of parsed GNTP Headers """ d = {} for line in data.split('\r\n'): match = GNTP_HEADER.match(line) if not match: continue key = match.group(1).strip() val = match.group(2).strip() d[key] = val return d def add_header(self, key, value): self.headers[key] = value def add_resource(self, data): """Add binary resource :param string data: Binary Data """ data = gntp.shim.b(data) identifier = hashlib.md5(data).hexdigest() self.resources[identifier] = data return 'x-growl-resource://%s' % identifier def decode(self, data, password=None): """Decode GNTP Message :param string data: """ self.password = password self.raw = gntp.shim.u(data) parts = self.raw.split('\r\n\r\n') self.info = self._parse_info(self.raw) self.headers = self._parse_dict(parts[0]) def encode(self): """Encode a generic GNTP Message :return string: GNTP Message ready to be sent. Returned as a byte string """ buff = _GNTPBuffer() buff.writeln(self._format_info()) #Headers for k, v in self.headers.items(): buff.writeheader(k, v) buff.writeln() #Resources for resource, data in self.resources.items(): buff.writeheader('Identifier', resource) buff.writeheader('Length', len(data)) buff.writeln() buff.write(data) buff.writeln() buff.writeln() return buff.getvalue() class GNTPRegister(_GNTPBase): """Represents a GNTP Registration Command :param string data: (Optional) See decode() :param string password: (Optional) Password to use while encoding/decoding messages """ _requiredHeaders = [ 'Application-Name', 'Notifications-Count' ] _requiredNotificationHeaders = ['Notification-Name'] def __init__(self, data=None, password=None): _GNTPBase.__init__(self, 'REGISTER') self.notifications = [] if data: self.decode(data, password) else: self.set_password(password) self.add_header('Application-Name', 'pygntp') self.add_header('Notifications-Count', 0) def validate(self): '''Validate required headers and validate notification headers''' for header in self._requiredHeaders: if not self.headers.get(header, False): raise errors.ParseError('Missing Registration Header: ' + header) for notice in self.notifications: for header in self._requiredNotificationHeaders: if not notice.get(header, False): raise errors.ParseError('Missing Notification Header: ' + header) def decode(self, data, password): """Decode existing GNTP Registration message :param string data: Message to decode """ self.raw = gntp.shim.u(data) parts = self.raw.split('\r\n\r\n') self.info = self._parse_info(self.raw) self._validate_password(password) self.headers = self._parse_dict(parts[0]) for i, part in enumerate(parts): if i == 0: continue # Skip Header if part.strip() == '': continue notice = self._parse_dict(part) if notice.get('Notification-Name', False): self.notifications.append(notice) elif notice.get('Identifier', False): notice['Data'] = self._decode_binary(part, notice) #open('register.png','wblol').write(notice['Data']) self.resources[notice.get('Identifier')] = notice def add_notification(self, name, enabled=True): """Add new Notification to Registration message :param string name: Notification Name :param boolean enabled: Enable this notification by default """ notice = {} notice['Notification-Name'] = name notice['Notification-Enabled'] = enabled self.notifications.append(notice) self.add_header('Notifications-Count', len(self.notifications)) def encode(self): """Encode a GNTP Registration Message :return string: Encoded GNTP Registration message. Returned as a byte string """ buff = _GNTPBuffer() buff.writeln(self._format_info()) #Headers for k, v in self.headers.items(): buff.writeheader(k, v) buff.writeln() #Notifications if len(self.notifications) > 0: for notice in self.notifications: for k, v in notice.items(): buff.writeheader(k, v) buff.writeln() #Resources for resource, data in self.resources.items(): buff.writeheader('Identifier', resource) buff.writeheader('Length', len(data)) buff.writeln() buff.write(data) buff.writeln() buff.writeln() return buff.getvalue() class GNTPNotice(_GNTPBase): """Represents a GNTP Notification Command :param string data: (Optional) See decode() :param string app: (Optional) Set Application-Name :param string name: (Optional) Set Notification-Name :param string title: (Optional) Set Notification Title :param string password: (Optional) Password to use while encoding/decoding messages """ _requiredHeaders = [ 'Application-Name', 'Notification-Name', 'Notification-Title' ] def __init__(self, data=None, app=None, name=None, title=None, password=None): _GNTPBase.__init__(self, 'NOTIFY') if data: self.decode(data, password) else: self.set_password(password) if app: self.add_header('Application-Name', app) if name: self.add_header('Notification-Name', name) if title: self.add_header('Notification-Title', title) def decode(self, data, password): """Decode existing GNTP Notification message :param string data: Message to decode. """ self.raw = gntp.shim.u(data) parts = self.raw.split('\r\n\r\n') self.info = self._parse_info(self.raw) self._validate_password(password) self.headers = self._parse_dict(parts[0]) for i, part in enumerate(parts): if i == 0: continue # Skip Header if part.strip() == '': continue notice = self._parse_dict(part) if notice.get('Identifier', False): notice['Data'] = self._decode_binary(part, notice) #open('notice.png','wblol').write(notice['Data']) self.resources[notice.get('Identifier')] = notice class GNTPSubscribe(_GNTPBase): """Represents a GNTP Subscribe Command :param string data: (Optional) See decode() :param string password: (Optional) Password to use while encoding/decoding messages """ _requiredHeaders = [ 'Subscriber-ID', 'Subscriber-Name', ] def __init__(self, data=None, password=None): _GNTPBase.__init__(self, 'SUBSCRIBE') if data: self.decode(data, password) else: self.set_password(password) class GNTPOK(_GNTPBase): """Represents a GNTP OK Response :param string data: (Optional) See _GNTPResponse.decode() :param string action: (Optional) Set type of action the OK Response is for """ _requiredHeaders = ['Response-Action'] def __init__(self, data=None, action=None): _GNTPBase.__init__(self, '-OK') if data: self.decode(data) if action: self.add_header('Response-Action', action) class GNTPError(_GNTPBase): """Represents a GNTP Error response :param string data: (Optional) See _GNTPResponse.decode() :param string errorcode: (Optional) Error code :param string errordesc: (Optional) Error Description """ _requiredHeaders = ['Error-Code', 'Error-Description'] def __init__(self, data=None, errorcode=None, errordesc=None): _GNTPBase.__init__(self, '-ERROR') if data: self.decode(data) if errorcode: self.add_header('Error-Code', errorcode) self.add_header('Error-Description', errordesc) def error(self): return (self.headers.get('Error-Code', None), self.headers.get('Error-Description', None)) def parse_gntp(data, password=None): """Attempt to parse a message as a GNTP message :param string data: Message to be parsed :param string password: Optional password to be used to verify the message """ data = gntp.shim.u(data) match = GNTP_INFO_LINE_SHORT.match(data) if not match: raise errors.ParseError('INVALID_GNTP_INFO') info = match.groupdict() if info['messagetype'] == 'REGISTER': return GNTPRegister(data, password=password) elif info['messagetype'] == 'NOTIFY': return GNTPNotice(data, password=password) elif info['messagetype'] == 'SUBSCRIBE': return GNTPSubscribe(data, password=password) elif info['messagetype'] == '-OK': return GNTPOK(data) elif info['messagetype'] == '-ERROR': return GNTPError(data) raise errors.ParseError('INVALID_GNTP_MESSAGE') SABnzbd-2.3.2/gntp/errors.py0000644000000000000000000000100713217005257013765 0ustar 00000000000000# Copyright: 2013 Paul Traylor # These sources are released under the terms of the MIT license: see LICENSE class BaseError(Exception): pass class ParseError(BaseError): errorcode = 500 errordesc = 'Error parsing the message' class AuthError(BaseError): errorcode = 400 errordesc = 'Error with authorization' class UnsupportedError(BaseError): errorcode = 500 errordesc = 'Currently unsupported by gntp.py' class NetworkError(BaseError): errorcode = 500 errordesc = "Error connecting to growl server" SABnzbd-2.3.2/gntp/notifier.py0000644000000000000000000002016113217005257014272 0ustar 00000000000000# Copyright: 2013 Paul Traylor # These sources are released under the terms of the MIT license: see LICENSE """ The gntp.notifier module is provided as a simple way to send notifications using GNTP .. note:: This class is intended to mostly mirror the older Python bindings such that you should be able to replace instances of the old bindings with this class. `Original Python bindings `_ """ import logging import platform import socket import sys from gntp.version import __version__ import gntp.core import gntp.errors as errors import gntp.shim __all__ = [ 'mini', 'GrowlNotifier', ] logger = logging.getLogger(__name__) class GrowlNotifier(object): """Helper class to simplfy sending Growl messages :param string applicationName: Sending application name :param list notification: List of valid notifications :param list defaultNotifications: List of notifications that should be enabled by default :param string applicationIcon: Icon URL :param string hostname: Remote host :param integer port: Remote port """ passwordHash = 'MD5' socketTimeout = 3 def __init__(self, applicationName='Python GNTP', notifications=[], defaultNotifications=None, applicationIcon=None, hostname='localhost', password=None, port=23053): self.applicationName = applicationName self.notifications = list(notifications) if defaultNotifications: self.defaultNotifications = list(defaultNotifications) else: self.defaultNotifications = self.notifications self.applicationIcon = applicationIcon self.password = password self.hostname = hostname self.port = int(port) def _checkIcon(self, data): ''' Check the icon to see if it's valid If it's a simple URL icon, then we return True. If it's a data icon then we return False ''' logger.info('Checking icon') return gntp.shim.u(data)[:4] in ['http', 'file'] def register(self): """Send GNTP Registration .. warning:: Before sending notifications to Growl, you need to have sent a registration message at least once """ logger.info('Sending registration to %s:%s', self.hostname, self.port) register = gntp.core.GNTPRegister() register.add_header('Application-Name', self.applicationName) for notification in self.notifications: enabled = notification in self.defaultNotifications register.add_notification(notification, enabled) if self.applicationIcon: if self._checkIcon(self.applicationIcon): register.add_header('Application-Icon', self.applicationIcon) else: resource = register.add_resource(self.applicationIcon) register.add_header('Application-Icon', resource) if self.password: register.set_password(self.password, self.passwordHash) self.add_origin_info(register) self.register_hook(register) return self._send('register', register) def notify(self, noteType, title, description, icon=None, sticky=False, priority=None, callback=None, identifier=None, custom={}): """Send a GNTP notifications .. warning:: Must have registered with growl beforehand or messages will be ignored :param string noteType: One of the notification names registered earlier :param string title: Notification title (usually displayed on the notification) :param string description: The main content of the notification :param string icon: Icon URL path :param boolean sticky: Sticky notification :param integer priority: Message priority level from -2 to 2 :param string callback: URL callback :param dict custom: Custom attributes. Key names should be prefixed with X- according to the spec but this is not enforced by this class .. warning:: For now, only URL callbacks are supported. In the future, the callback argument will also support a function """ logger.info('Sending notification [%s] to %s:%s', noteType, self.hostname, self.port) assert noteType in self.notifications notice = gntp.core.GNTPNotice() notice.add_header('Application-Name', self.applicationName) notice.add_header('Notification-Name', noteType) notice.add_header('Notification-Title', title) if self.password: notice.set_password(self.password, self.passwordHash) if sticky: notice.add_header('Notification-Sticky', sticky) if priority: notice.add_header('Notification-Priority', priority) if icon: if self._checkIcon(icon): notice.add_header('Notification-Icon', icon) else: resource = notice.add_resource(icon) notice.add_header('Notification-Icon', resource) if description: notice.add_header('Notification-Text', description) if callback: notice.add_header('Notification-Callback-Target', callback) if identifier: notice.add_header('Notification-Coalescing-ID', identifier) for key in custom: notice.add_header(key, custom[key]) self.add_origin_info(notice) self.notify_hook(notice) return self._send('notify', notice) def subscribe(self, id, name, port): """Send a Subscribe request to a remote machine""" sub = gntp.core.GNTPSubscribe() sub.add_header('Subscriber-ID', id) sub.add_header('Subscriber-Name', name) sub.add_header('Subscriber-Port', port) if self.password: sub.set_password(self.password, self.passwordHash) self.add_origin_info(sub) self.subscribe_hook(sub) return self._send('subscribe', sub) def add_origin_info(self, packet): """Add optional Origin headers to message""" packet.add_header('Origin-Machine-Name', platform.node()) packet.add_header('Origin-Software-Name', 'gntp.py') packet.add_header('Origin-Software-Version', __version__) packet.add_header('Origin-Platform-Name', platform.system()) packet.add_header('Origin-Platform-Version', platform.platform()) def register_hook(self, packet): pass def notify_hook(self, packet): pass def subscribe_hook(self, packet): pass def _send(self, messagetype, packet): """Send the GNTP Packet""" packet.validate() data = packet.encode() logger.debug('To : %s:%s <%s>\n%s', self.hostname, self.port, packet.__class__, data) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(self.socketTimeout) try: s.connect((self.hostname, self.port)) s.send(data) recv_data = s.recv(1024) while not recv_data.endswith(gntp.shim.b("\r\n\r\n")): recv_data += s.recv(1024) except socket.error: # Python2.5 and Python3 compatibile exception exc = sys.exc_info()[1] raise errors.NetworkError(exc) response = gntp.core.parse_gntp(recv_data) s.close() logger.debug('From : %s:%s <%s>\n%s', self.hostname, self.port, response.__class__, response) if type(response) == gntp.core.GNTPOK: return True logger.error('Invalid response: %s', response.error()) return response.error() def mini(description, applicationName='PythonMini', noteType="Message", title="Mini Message", applicationIcon=None, hostname='localhost', password=None, port=23053, sticky=False, priority=None, callback=None, notificationIcon=None, identifier=None, notifierFactory=GrowlNotifier): """Single notification function Simple notification function in one line. Has only one required parameter and attempts to use reasonable defaults for everything else :param string description: Notification message .. warning:: For now, only URL callbacks are supported. In the future, the callback argument will also support a function """ try: growl = notifierFactory( applicationName=applicationName, notifications=[noteType], defaultNotifications=[noteType], applicationIcon=applicationIcon, hostname=hostname, password=password, port=port, ) result = growl.register() if result is not True: return result return growl.notify( noteType=noteType, title=title, description=description, icon=notificationIcon, sticky=sticky, priority=priority, callback=callback, identifier=identifier, ) except Exception: # We want the "mini" function to be simple and swallow Exceptions # in order to be less invasive logger.exception("Growl error") if __name__ == '__main__': # If we're running this module directly we're likely running it as a test # so extra debugging is useful logging.basicConfig(level=logging.INFO) mini('Testing mini notification') SABnzbd-2.3.2/gntp/shim.py0000644000000000000000000000170213217005257013413 0ustar 00000000000000# Copyright: 2013 Paul Traylor # These sources are released under the terms of the MIT license: see LICENSE """ Python2.5 and Python3.3 compatibility shim Heavily inspirted by the "six" library. https://pypi.python.org/pypi/six """ import sys PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] == 3 if PY3: def b(s): if isinstance(s, bytes): return s return s.encode('utf8', 'replace') def u(s): if isinstance(s, bytes): return s.decode('utf8', 'replace') return s from io import BytesIO as StringIO from configparser import RawConfigParser else: def b(s): if isinstance(s, unicode): return s.encode('utf8', 'replace') return s def u(s): if isinstance(s, unicode): return s if isinstance(s, int): s = str(s) return unicode(s, "utf8", "replace") from StringIO import StringIO from ConfigParser import RawConfigParser b.__doc__ = "Ensure we have a byte string" u.__doc__ = "Ensure we have a unicode string" SABnzbd-2.3.2/gntp/version.py0000644000000000000000000000020313217005257014133 0ustar 00000000000000# Copyright: 2013 Paul Traylor # These sources are released under the terms of the MIT license: see LICENSE __version__ = '1.0.3' SABnzbd-2.3.2/gntp/__init__.py0000644000000000000000000000000013217005257014200 0ustar 00000000000000SABnzbd-2.3.2/icons/nzb.ico0000644000000000000000000006161313217004753013540 0ustar 00000000000000 hV   F00 % D(  @#aCB|B|B|Je̜e̜e̜e̜B|"^AA-A-B|B|Ue̜e̜e̜e̜A-A-B|B|`Șe̜e̜e̜e̜`ȗB|B|B|Ie̜e̜e̜e̜e̜e̜HB|B|Te̜e̜e̜e̜e̜e̜SB|B|_ȗe̜e̜e̜e̜e̜e̜_ǖB|B|e̜e̜e̜e̜e̜e̜e̜d˛B|B|e̜e̜e̜e̜e̜e̜e̜e̜B|(0 ` AzAzAzAzAzAz,,,---&&& '''111,,,%%%111AzAzAzAzAzAzTgϟgϟgϟgϟ^AzAzAzAzAzAzAzAzTfϞfϞfϞfϞgϟgϟAzAzAzAzAzAzAzAzAzD}\Ɣe̜e̜e̜e̜e̜gϟAzAzAzAz@yAzIcʚe̜e̜e̜e̜e̜e͜`ƖBxu@xIbʙe̜e̜e̜e̜e̜e̜e̜e̜aɘG>u@xQe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜O>uAy[œf̜e̜e̜e̜e̜e̜e̜e̜e̜f̝Yđ?vF~bʙe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜aɘCyNe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜KYfΞf͝f͝f͝f͝f͝f͝f͝f͝f͝f͝fΞUfΞfΞfΞfΞfΞfΞfΞfΞfΞfΞfΞfΞfΞfΞ( @ &&&MM&&MMMM&ZB|B|B|B|B|B|B|C|cʚe̜e̜e̜e̜C|C|B|B|ZB|B|B|B|B|B|B|C|cʚe̜e̜e̜e̜e̜e̜C|B|B|B|ZB|B|B|B|B|B|B|B|Le̜e̜e̜e̜e̜e̜e̜LB|B|B|B|ZB|B|B|B|B|B|B|B|B|We̜e̜e̜e̜e̜e̜e̜e̜B|B|B|B|B|B|B|B|B|B|B|B|B|B|B|bʙe̜e̜e̜e̜e̜e̜e̜e̜aəB|B|B|B|B|B|B|B|B|B|B|B|B|B|Ke̜e̜e̜e̜e̜e̜e̜e̜e̜e̜JB|B|B|B|B|B|B|B|Ve̜e̜e̜e̜e̜e̜e̜e̜e̜e̜UB|B|B|B|B|B|B|B|aəe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜`ɘB|B|B|B|B|B|B|Je̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜IB|B|B|B|B|B|Ue̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜TB|B|B|B|B|B|aɘe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜`ȗB|B|B|B|B|Ie̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜HB|B|B|B|Ue̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜SB|B|B|B|`ȗe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜_ǖB|B|HHe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜d˛GHHTe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜RHH_ǖe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜^ǕHHd˛e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜d˛He̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜?(0` %   B|B|  B|B|B|B| B|B|b̚_ʗB|B|B|B|B|b̚b̚B|B|B|  &&&      """       B|C}C}C}C}C}C}C}C}C}C}C}C}fΝfΝfΝfΝfΝfΝfΝfΝfΝfΝC}C} B|B|B|B| B|C~C}C}C}C}C}C}C}C}C}B}D~\ǕfΞfΝfΝfΝfΝfΝfΝfΝfΝfΝfΞC} C}C}C}B|B|  B|C~C}B}B}B}B|B|B|B|B|B|B|Ibʚe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜C}  C}B}B}C}B|B| B|B|B|B|B|B|B|B|B|B|B|B|B|B|Re̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜dʛB|B|B|B|B|B|B|      C}B|B|B|B|C}[œf̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜f͝C}B|B|B|B|Hbʙe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜fΝ_ȗD}AzAzAzAzB{C}B|B|B|B|Qe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜d˛MB|B|B|B|A{C}B|B|B|C}[Ēf̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜VB|B|B|B|A{C}B|B|B|Hbʙe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜_ȖEB|B|B|A{C}B|B|A|Pe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜d˛LA|B|B|A{C}B|B|C}ZĒf̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜UB|B|B|A{C}B|B|Gaɘe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜^ǖE~B|B|A{C}B|A|Oe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜d˛KB|B|A{C}B|C}YÑf̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜UB|B|A{C}B|Gaɘe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜]ǕD~B|A{C}A|Oe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜c˚KB|A{C}B|XÐf̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜TB|A{B}F`ȗe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜]ƔD~A{B}Nd̛e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜cʚJA{C~Wf̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜SA{G`ȗe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜\ƔC}Nd˛e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜cʚIWĐf̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜Q`˙f͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝e͝f͝[œe̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜e̜?@PNG  IHDR\rfIDATx \Uǿ޻zKo& }322308((8ǃ0qA8@pΉCD a ($L/}[]}?BBH}9**uT!!ҰJϨtJߵ}A Rg^ߪt$SJe"IUؾMt d^Q鵶/ ~@Pt !āva__NB>ҏl_ ~!~aJ۾ /lTTA!Ɲ6 VHm}?fiKvq VYIJod>m_ %#CnVikixU$2;7-dk 8ZkOnuS~-'F'7dS 8 yU5R}XXX^mlN#kU4ևMv!Ęٹ%>ds ȹ aio`@İN5@16H]]t0 yc! ýR0?BXd!Df WSV0@BeU3 069"#*BU֣}uOWRp%@c]H0dO$Qث){@\5\U!=\ $[Хm3)AVZSkMv'ds+3`.WپvSƧdx|p=€jPYQiH- Y ZDohRPJحYZm_?}W Y @Z  P7/ӳr`쑵ttI]MaQ lN#kDf/Ȥ*PIU5- :>82 攠쑓ttKmMɡH3?쑓@YZB bf\G=`PSU+: p:)c!tSQY P}/ģ؟(_G͍-j}/ărfBύG^_P $2`5 H ?="ТB O@wELJRțjT)KLd?@` ̀]=w !C~Q!76 74۾' T?2%FG@DaB0rG^KSնX?sܖG^0KPSC}5`< aI02>$cSFR{ af = "Ю€FeǬ*_0, @\/#ˈ|(H>UEQGJX>J~?({L%P].'~ = &dzd~HqY= Z@?m')0ۯ3QPCkC J}){T8<$HJQj_ @T0dA#00OGT`?Dz( Fx5t jcPF zh0Z*xɁ?~="$0 (-0/fͶ({Eӄa0RJ?P(^cP:({M J, =&ECx) es<` F=z1Py E@@/#ޥ%f>յ` ` q,%NK@'t /ǣQtTր .#k :` BZğ߇h^Gأ*hV#@Êjկ߂ϜPU FlSP"jpc'n7Y5, .5}ؠ*c7 JXF\$D핹5֦6ij`z?>2` 둁!0`گ񩱼l`@^=aU]B: iU{_et6aт Ak@ς~1O@ú   eMJ3mPx,-9,C İN=< ˇc0#H~Q-9({xBCBuM\Fc C* 2}c]Ho?BBB~`aW>*P XH({xF%x4̀0Io?Th({xH[p]~] 9SCjCNAvޜ6LHa[ ({xL`l@%k$}zb|=<' Dk3 _( @" hVa@'ShgA!3a R\PǴߘX1`O a Ĝ KTPeMI61 (.*Y)kxVX/ `cى@óH* |'[ 5I1̸ 5<-`lV&3- @EB:Z P߲ߦP@sc4Z.X9?` Vݺ4@ bt){x^D@ G+ ({x^!BR/X (kBl2  z϶bx#cI޿8ḿh$C~Q1p!Rvf![#qԕpJ/Y:c'*Ud*]ҡb^K0siƧ췽B^DH>RJoe$P0 o?i>GT:fW0<ÄI>90⿾ Ti=-v>hr; B0QÀ3ĢcS#E{3R}S"t'ާhr;HX?3PpldZFzm_*]<(xIk`@E@ qyw/ɋdd`R$!*iWK!9Y*}](*ŚJ-t6a9*-WG ~ X]!G.7JEe@m_R@J ΒZ@!]=zAL+>tm~欒)PdH] A) 5_lrV[;&l_FGYa$Ơ\3=kXo&:rXҋ{?rOO.xypk`Bؼ釷hK%Y{ԅ䲻N{`p+~TN>EzwھGT> nm21LFvJ\-tnЏioP].TTVÛ_^S*V:\oRF7] 2).T[bjKwqH&T2?$@V@}w^'.n[u3Y߹Iq7l^>AR dN.dJ,#ޡJ!i7>syq禿bTbN󴽦^6w})󬫺tD>}|^Gj_ DUx ԫ0 0 Q%|&V%OX@2ye7b1KT{Xi6D F 'P@g 0`9;/mOJ;x+ll{h vE`tfP$׏}FjedT|V3N{Ćk G %a9 doOǭFA fZ:d|J`9րJ.#~3~7oxNEsG*NJt^IWU2mrRH]* h2[N$&|z^%t3j0w_qRBDukÀPIf_m)yY1|nDsy ,! o햳.},=+s2 H@a1v4]0ުGݜA}pyS4540ex O_wh$f'w{:75`0qǟZCGP"z.,#0@C,{U~yK27cT:],@W\ I>D<]K   ?ܿW~2;5f*}6vxBePBN=wK][%j2<?O~~23u*-s2_0,Rxߡrه$T*Q u%24VJW{ĸ_d^m"hF\P{=< gu5Vޜs TUi$p{_:*Nk?l/\sOe}۽"ZmFh9t앭w]_Ƌ"h _:9|c.4 7W TKAnDDf+"|̛/-bBy>U`΄;gD]U<.pJ-sY<*(eOeƳH.S"c^VU WO`~g6;f#WUz;&UNnpJ۾SRP٣!nwr# Ksl))O(ytn>t;nM9?Vq\MKKԲ_b!Oo]ի/q0EƭbX ̡|``(s(s(@CC   'PPP>00 99O̡̡|``  '@9?// (sE,:s)sF}}XwTUUI4L̡RA ``r 0P@&((s(s(sP2A8@CC(     @a(LP]IehhSDdp(VYnA#ٳG}B(_}Pi(r P.A>(4P@ (@Pr@( \H@}Pi(r @[qkA(djjsXx)4P!#@,(,3@( PP9(B8C @,(,3@( PP9(B8C @,(,3@( PP9QXo]rRFy1/. U(s2#9@9(CC?9@9(CC?9@9(CC?9@9(CC?9@9(CCT @78z]1iǍ/g&NT!W餌t˜ |*f]\gUPUJ0!˘WNnqJeN !xU5nwr+ *mQBbJɭ}El-!d 4tdcuQ4wMJՒqvW* <>C}!)$ʳ|VDTUQlC]Uj$*5-U:2+s*g4z,_Wڡ(X(@F/t$LdzoQdIT^WUM.1,\|$&.`AVyY(ΩmN]|V5b_6wl;Uz@qr~@x[b2~Wn~^zݽ/|Hb UpYŵ >rLM}P0Uo 037-}G3sgl~AnGd|p$J-‡ IAI3]_(;hL vP|!.#26*cLɱ:|BUr]'ޠÞAj푪sOQ9\ 7~t θtTоQyoJ M%*lwHc})fUʡw *tc2(TZ/<_p%Pk\z۩Kƺ HNK]wIيߜ&$OzJF W+eO?W@~o/Ļ@Kw\|%ЮJ["YG?qoSYW+F[$|)ƕ4n<1ۛW34{s` :;(|1Ǖ:mpR~ ('€6rp~2!7SH3Oq(*$~u㲒:tHcmhY0H.o}Ff>y$<ٓP ;.EqiK{xղǧFex|/<: T$h06~h$3p%Z~A@g t < @F铙n`_o<'O?f:I ~X ?$ǵyW$[0'5SdآtĈ'>q$Urޤ%&> j[ /_u3Uw[Qgtʻ8Jg`en }2=Ц=/Kl5De%—Ok_]\r֥o l$€]?yݻq=6]>/ο$g2 }[nlPĽ>v+vI43=\r"~C>/ߠ5 wrHZyo<=;en8'sOrFXc Trk嬏'l9LnS%\tL\H?Sv=3(SsnD,ZUHB7SBe7 /tɷ |M$D-}r/Jm|ZhFl~e_tN$1sǴ%M]F ͉IENDB`SABnzbd-2.3.2/icons/sabnzbd.ico0000644000000000000000000006053213217004753014371 0ustar 00000000000000 hV   F00 % D(  @afC_C_ ((((C_C_#(((("(((((((((((("((((((!(((((((((((((((((0 `  222222 (((((((((()((((($((((((#(((((((()(((((()$((((((((#(((((((((()(((((((()#((((((((((#(((((((((((')(((((((((()))))))))))))))( @ &&&&&&Z((((((ZZ%(((((($ZZ (((((((( ZZ((((((((Z%(((((((($ (((((((((( (((((((((($((((((((((# ((((((((((((((((((((((((#(((((((((((("(((((((((((((((((((((((((((("((((((((((((((!((((((((((((((((((((((((((((((((!(((((((((((((((( ((((((((((((((((('((((((((((((((((((((?(0` %   ! !!           (((((((((()((((((((()#(((((((((((((((((((((((()((((((((((((#((((((((((((()!'((((((((((((((' )(((((((((((((()"((((((((((((((((! '((((((((((((((((' )(((((((((((((((()!((((((((((((((((((  '((((((((((((((((((& )(((((((((((((((((((!((((((((((((((((((() '((((((((((((((((((((& )((((((((((((((((((((( ((((((((((((((((((((() &((((((((((((((((((((((& (((((((((((((((((((((((()(((((((((((((((((((((() &((((((((((((((((((((((((%(((((((((((((((((((((((((()(((((((((((((((((((((((()((((((((((((((((((((((((((((?@PNG  IHDR\rfIDATx eWYǿ7 3=[gBÌJA5@HBXdߔFUd!X*J%B)A,!df2az׋:=o99Lw{߹ݳҲ|gN~O4]_S 鬦k&Mg|gb@eM?ti@UMtBlX5 ![8Lߙ hw&\MG4];T˚^iwFlI鍾3AH4}V-3bCLGAߙ ĂOiUӺT#&Lk B,4MH5b^+}`d`vtH$6fe~iǎhz[J˚CdZaHl9*_hO]"&V)Tt@a@(:s"g)OT?FDzw+i6r_:z ar.Kzᆢ.D087ԂVg'wE66LGx6t  ˅ÿR;}Dgrۯ)&qXTܹR b:\=(.#z=ڻ| 'Ef~ZO?jحa0 A?Q^O]"CʬkRvkpRTP?SO`pHψ0 eIeRDEv$3PR@x~ XHp 45T7~G{5 dJ:١TVrP^IGmS%$!g^`!tiM`HMMP01}QJP^IOh@ E`y֌بQ  0$&J + ӴsiQrfW_8t+] Zl }\?/}J`0 hAY3+` M(/$ oF 2 h=J#f0ZUP^iڻ aorfO_،Gc,#a@g0 h!Nk6W#7*?HV੏.@xqa ZQ F.¦?'$ 7+1 h~-P^iR⤹S/VܷXt.#TL3+W+|W4+B)4V;}'iTk۞J[XFa@S1ɲ5 W/4Bx@ %-@aZ]4IV(d#2ݾ4s׹  " `s`STOJv7b:=,+uT)’01ə%o f Cfz4ɲGͿBx%[$a,=ej)GX: k0 ?ξ(d/zPTlT,? + ˇ'ˈ3 y'jpWkVfh[L(@*NI:=^P^#$ 8`%egL_evKÏpP?&W< @2H,~)Z30G®)@3/ZLW< @LS zvP^+ @k@s"Sg{ ~Q5 fv(10A~aF@xſ0CZHάQ/|H€q3YÀXQP^/i0k0 <'ظ^@>d#FU _C# ` 0 (OkpAx% 5I੟,z0Vf?7S^ GI0neG @@N v>'$?h4 +a aZ_3W >+ |}QK-h ~ Jx5/cem 80iArf/f+)'?V SPǼs}'0IөlVW_YU00 YFi!b/N3Z a ` fxL%W&| %~^ + SSÀ ș%򯇯 o/dW A  xuP^ [Ip, B^iSQӢVb bi?Mx%|`!,#i̴Jxș'[ Jt3 h&@_P^CIcOT %Q,"YJ(dX]὚鑚0 )p_#N)a@L_X2$~%i;`ktV3L0)M€!a"07 <пr^ *tcF+W8PzL IxP6KIQ(ygLP@0zˈ^?BV"@X0wŠJPH'҅0f(>igIN6 txHE' J=1@S| ]OB~G୚>X-^28`hp8' ;%YɉWE~9$NJ"W_n~D&W NIߌd`G=#CKZ{믉ܦ"lk`>ET<׸zlzy%߇f{l�F_UxP{oy]5Pc (( j3_ЇkPme#|%ˈkX-9%lTW;.jS"+Zyr-󆓽X譚{78 <0;Rx_[.rD^ 'R<%t[m=M+ .Ml53kH"o`0,04mx{!WPVBzD>Bo45k̿&shjzC^4YY_KXv$aYA'k;@I|Ěk.i}˜ Y+M"/ItValO|F(v`,Gm="\{?Y ~z^Q x?(9){:{ntNA\F,6`,@bVGcYkUrNZ)Ohmˮ?`NjP@:zե`ffFW%gfEuȜ})rz92_MePߩN߹LOO`cǫ.3[|,8myM/v6L"E"!@9:{ ˈ3 (P کi-9.?izA㭲e-W]"r7(䰌8À2P2&2Ϳ|Us+* h %P El~Ĕ^+rӖtmуȿP烾0`@ 9zioEK_&`ݧ9{ zW zsJP(aп#-y(vQ\\d/](`\@/ p7:šϥP,ƘTpv_$@$ 2AlP{=GInK1k6o 7]+v2&@BEӖ?!) n}_#,A&'a(,/z]9m|.xk*_聼TU0oȇoJ0`@v%^ּe=w Ⱂ&Sx D> im 0 FK Po|iK4 5L r RUWE2K9 YS7FX/m`ltd2-TPr#}q3![>0+ⷝ6E 4'(M+2㒉^}cD=pVD:Q?*.,w!&`jϥ}gE^19dNBuף B1cSWShlH9W|L|(ED(4Puo Ng$d.3s)Mw}!j8k@Bp` |Q!@C/ ({(TE`j(R=@BH5_@PP  |Q!@C/ ({(T2JOHPP+3,h\؀6Ʌj<ڵ+pT-kkkP+3`-q"v4N ۚ#N {4G2``aM7Slfި(({(PP+SjoQ@@TNM76SlCMn @@TgJPÏ8eZ]H.7*PVrēIC `O z4`H]@LYcbեz@+B%D  ==@$PPP@CCD`` ==@$PPP@CCD`` ==@$P `ffF|g  ؟ұ19y,{K/Y Pqadtxx8*ju)H2::*9(vd[ ̬߄D>3gTF޵LhB>׍jkz%uZ~Mo}m8Zg}|-!dr=ӾTl d1^:Wzżt@{_'At֍ko%3V.hj͞,vVYlbFoN qPvgj+ dz=EL) ?nts x#Ր5?b,k~N4mMH^w\/ Tahuk[v_^[NI6S{}X +j<$pV{TGJdX{1h]SGyT;:j+=“(7%0ǎ6^5*@n%VUuUuܞ2_G~Pxy 6 u/5j[~zFϝ\w9V^'i,amP}RdE! v[@K>?w͌FKy7b`u} $\d`]*LG4-Idվ Z@\Pbv Q [洎0a@gϝ}>"2Wh%~$/:[p|*W賅SOky/J8I]"wX%0,M|:4 .譐_0?~XRl}(0$@kWzxXӏy-g[cAËN-q{ =BÀ:+vgD};+pxI/@Gi ȝp^SL/-_xJ 9;_[N/< C[vVg'X51-rU} P$/;Γ@N vnF?o~F)ǽV@SS'NxAϿe:{b,2yT 9z[x?E/X8I/r h+b=Ys~x/E/ZYO e~P$?YC".^PGI/~a>A VTd\6{8PMqJ6k `d׊-*L<]"w/ӷ;'/``-,[yߍO[N\XK]/V
$T('version'): $version [$build]
$T('uptime'): $uptime
$T('confgFile'): $configfn
$T('parameters'): $cmdline
$T('pythonVersion'): $sys.version[:120] [$getpreferredencoding()]
OpenSSL: $ssl_version
$T('warning') $T('explain-nosslcontext')
$T('opt-multicore-par2') $T('notAvailable') $T('explain-getpar2mt') ${helpuri}installation/multicore-par2
Python Cryptography: $T('notAvailable')
yEnc: $T('notAvailable')
SABYenc: $T('notAvailable')
$T('opt-enable_unzip'): $T('notAvailable')
$T('opt-enable_7zip'): $T('notAvailable')
$T('homePage') https://sabnzbd.org/
$T('menu-wiki') https://sabnzbd.org/wiki/
$T('menu-forums') https://forums.sabnzbd.org/
$T('source') https://github.com/sabnzbd/sabnzbd
$T('menu-irc') #sabnzbd on irc.synirc.net $T('or') (webchat)
$T('menu-issues') https://sabnzbd.org/wiki/introduction/known-issues
$T('menu-donate') https://sabnzbd.org/donate
Copyright © 2008-2017 The SABnzbd Team <team@sabnzbd.org>

$T('yourRights')

SABnzbd-2.3.2/interfaces/Config/templates/config_cat.tmpl0000644000000000000000000001772713217005257021467 0ustar 00000000000000

$T('explain-catTags2')
$T('explain-catTags')


$T('explain-relFolder'): $defdir
class="sorting-row">
$T('category') $T('priority') $T('mode') $T('script') $T('catFolderPath') $T('catTags')

SABnzbd-2.3.2/interfaces/Config/templates/config_folders.tmpl0000644000000000000000000001572613217005257022353 0ustar 00000000000000

$T('userFolders')

$T('explain-folderConfig')

$T('base-folder'): $my_home
$T('explain-download_dir')
$T('explain-download_free')
$T('explain-complete_dir')
$T('explain-permissions')
$T('explain-dirscan_dir')
$T('explain-dirscan_speed')
$T('explain-script_dir')
$T('explain-email_dir')
$T('explain-password_file')
      

$T('systemFolders')

$T('explain-folderConfig')

$T('base-folder'): $my_lcldata
$T('explain-admin_dir1') $T('explain-admin_dir2')
$T('explain-log_dir')
$T('explain-nzb_backup_dir')
SABnzbd-2.3.2/interfaces/Config/templates/config_general.tmpl0000644000000000000000000004721513217005257022330 0ustar 00000000000000

$T('webServer')

$T('restartRequired')

$T('explain-host')
$T('explain-port')
0 then 'checked="checked" data-original="1"' else ""#-->/> $T('explain-enable_https')
$T('explain-web_dir')  $caller_url
$T('explain-language')
$T('explain-ask-language') https://sabnzbd.org/wiki/translate
$T('base-folder'): $my_lcldata
$T('explain-https_port')
$T('explain-https_cert')
$T('explain-https_key')
$T('explain-https_chain')

$T('security')

$T('restartRequired')

$T('explain-web_username')
$T('explain-web_password')
$T('explain-inet_exposure').replace('. ','.
'+$T('warning').upper()+' ')
$T('explain-local_ranges')
$T('explain-apikey')
$T('explain-nzbkey')

$T('cmenu-switches')

0 then 'checked="checked"' else ""#--> /> $T('explain-auto_browser')
$T('explain-check_new_rel')
"> 0 then 'checked="checked"' else ""#--> /> $T('explain-enable_https_verification')

$T('tuning')

$T('explain-bandwidth_perc')
$T('explain-cache_limitstr').replace("64M", "256M").replace("128M", "512M")
SABnzbd-2.3.2/interfaces/Config/templates/config_notify.tmpl0000644000000000000000000006525013217005257022222 0ustar 00000000000000
0 then 'checked="checked"' else ""#--> />
0 then '' else 'style="display:none"'#-->>
$T('affectedCat')

$T('cmenu-email')

0 then '' else 'style="display:none"'#-->> $T('affectedCat')
0 then 'checked="checked"' else ""#--> /> $T('explain-email_full')
0 then 'checked="checked"' else ""#--> /> $T('explain-email_rss')
$T('explain-email_dir')
$T('explain-email_server') ($T('host'):$T('srv-port'))
$T('explain-email_to')
$T('explain-email_from')
$T('explain-email_account')
$T('explain-email_pwd')

$T('section-NC')

0 then 'checked="checked"' else ""#--> />
0 then '' else 'style="display:none"'#-->>
$show_notify_checkboxes('ncenter')

$T('section-AC')

0 then 'checked="checked"' else ""#--> />
$show_cat_box('acenter')
0 then '' else 'style="display:none"'#-->>
$show_notify_checkboxes('acenter')

$T('section-OSD')

0 then 'checked="checked"' else ""#--> />
$show_cat_box('ntfosd')
0 then '' else 'style="display:none"'#-->>
$show_notify_checkboxes('ntfosd')

$T('section-NScript')

0 then 'checked="checked"' else ""#--> />
$T('explain-nscript_enable')
$T('readwiki') $show_cat_box('nscript')
0 then '' else 'style="display:none"'#-->>
$T('explain-nscript_script')
$T('Optional') - $T('explain-nscript_parameters')
$show_notify_checkboxes('nscript')

$T('growlSettings')

0 then 'checked="checked"' else ""#--> />
$show_cat_box('growl')
0 then '' else 'style="display:none"'#-->>
$T('explain-growl_server')
$T('explain-growl_password')
$show_notify_checkboxes('growl')

$T('section-Prowl')

0 then 'checked="checked"' else ""#--> />
$T('explain-prowl_enable') $show_cat_box('prowl')
0 then '' else 'style="display:none"'#-->>
$T('explain-prowl_apikey')

$T('section-Pushover')

0 then 'checked="checked"' else ""#--> />
$T('explain-pushover_enable') $show_cat_box('pushover')
0 then '' else 'style="display:none"'#-->>
$T('explain-pushover_token')
$T('explain-pushover_userkey')
$T('explain-pushover_device')
$T('explain-pushover_emergency_retry')
$T('explain-pushover_emergency_expire')

$T('section-Pushbullet')

0 then 'checked="checked"' else ""#--> />
$T('explain-pushbullet_enable') $show_cat_box('pushbullet')
0 then '' else 'style="display:none"'#-->>
$T('explain-pushbullet_apikey')
$T('explain-pushbullet_device')
$show_notify_checkboxes('pushbullet')
SABnzbd-2.3.2/interfaces/Config/templates/config_rss.tmpl0000644000000000000000000010634713217005257021524 0ustar 00000000000000

$T('explain-RSS')

  $T('name') $T('feed') URL  
"> ">
rel="$feed_item" /> $feed_item
$uri

  $T('Next scan at:') $rss_next $T('explain-rss_rate')

$T('cmenu-rss') » $active_feed

$error
  $T('rss-order') $T('rss-type') $T('rss-filter') $T('category') $T('priority') $T('mode') $T('script')  
">
/>   $T('Incorrect filter')

  • $T('rss-matched')
  • $T('rss-notMatched')
  • $T('rss-done')
$T('link-download') $T('rss-filter') $T('size') $T('sort-title') $T('category') $T('nzo-age')
$job['rule'] $job['skip'] $job['size_units'] $job['title'] $job['cat'] $job['age']
$T('none')
$T('link-download') $T('rss-filter') $T('size') $T('sort-title') $T('category') $T('nzo-age')
$job['rule'] $job['skip'] $job['size_units'] $job['title'] $job['cat'] $job['age']
$T('none')
$T('rss-added') $T('size') $T('sort-title') $T('category') $T('source')
$job['time_downloaded'] $job['size_units'] $job['title'] $job['cat']
$T('none')
SABnzbd-2.3.2/interfaces/Config/templates/config_scheduling.tmpl0000644000000000000000000001711613217005257023035 0ustar 00000000000000 <% import time t = time.localtime() hour = t[3] if hour != 23: hour += 1 else: hour = 0 %>

$T('addSchedule')

 : 






$T('currentSchedules')

"> 0 then 'checked="checked"' else ""#-->>
$taskinfo[$schednum][1]:$taskinfo[$schednum][2]$taskinfo[$schednum][3] $taskinfo[$schednum][4]
SABnzbd-2.3.2/interfaces/Config/templates/config_server.tmpl0000644000000000000000000006765513217005257022233 0ustar 00000000000000

$T('addServer')

$T('srv-enable')
$T('explain-ssl')
$T('explain-svrprio')
$T('days')
$T('seconds')
advanced-settings"> $T('explain-ssl_verify').replace('. ', '.
')
$T('srv-explain-send_group')
$T('explain-optional')
">
">

$server['displayname']

$server['priority'] $T('srv-priority'):
/>
/> $T('explain-ssl')
$T('explain-svrprio')
$T('days')
$T('seconds')
advanced-settings"> $T('explain-ssl_verify').replace('. ', '.
')
/> $T('explain-optional')
/> $T('srv-explain-send_group')
$T('srv-bandwidth'):
$T('total'): $(server['amounts'][0])B
$T('today'): $(server['amounts'][3])B
$T('thisWeek'): $(server['amounts'][2])B
$T('thisMonth'): $(server['amounts'][1])B
:
SABnzbd-2.3.2/interfaces/Config/templates/config_sorting.tmpl0000644000000000000000000007333513217005257022402 0ustar 00000000000000

$T('seriesSorting')

$T('affectedCat')

$T('ft-download'): $complete_dir
0 then 'checked="checked"' else ""#--> />


 
$T('sort-meaning') $T('sort-pattern') $T('sort-result')
$T('show-name'): %sn $T('show-sp-name') ($T('case-adjusted'))
  %s.n $T('show-dot-name') ($T('case-adjusted'))
  %s_n $T('show-us-name') ($T('case-adjusted'))
$T('show-name'): %sN $T('show-sp-name')
  %s.N $T('show-dot-name')
  %s_N $T('show-us-name')
$T('show-seasonNum'): %s 1
  %0s 01
$T('show-epNum'): %e 5
  %0e 05
$T('ep-name'): %en $T('ep-sp-name')
  %e.n $T('ep-dot-name')
  %e_n $T('ep-us-name')
$T('fileExt'): %ext avi
$T('orgFilename'): %fn $T("sort-File")
$T('orgJobname'): %dn
$T('lowercase'): {$T('TEXT')} $T('text')

$T('movieSort')

$T('affectedCat')

$T('ft-download'): $complete_dir
0 then 'checked="checked"' else ""#--> />
0 then 'checked="checked"' else ""#--> />
 
$T('sort-meaning') $T('sort-pattern') $T('sort-result')
$T('sort-title'): %title $T('movie-sp-name')
  %.title $T('movie-dot-name')
  %_title $T('movie-us-name')
$T('year'): %y 2009
$T('extension'): %ext avi
$T('decade'): %decade 00
  %0decade 2000
$T('orgFilename'): %fn $T('sort-File')
$T('orgJobname'): %dn
$T('lowercase'): {$T('TEXT')} $T('text')
$T('multiPartLabel') $T('sort-pattern') $T('sort-result')
$T('partNumber'): %1 1

$T('dateSorting')

$T('affectedCat')

$T('ft-download'): $complete_dir
0 then 'checked="checked"' else ""#--> />

 
$T('sort-meaning') $T('sort-pattern') $T('sort-result')
$T('show-name'): %t $T('show-sp-name')
  %.t $T('show-dot-name')
  %_t $T('show-us-name')
$T('year'): %y 2009
$T('month'): %m 1
  %0m 01
$T('day-of-month'): %d 2
  %0d 02
$T('decade'): %decade 00
  %0decade 2000
$T('orgFilename'): %fn $T('sort-File')
$T('orgJobname'): %dn
$T('lowercase'): {$T('TEXT')} $T('text')
SABnzbd-2.3.2/interfaces/Config/templates/config_special.tmpl0000644000000000000000000000647213217005257022333 0ustar 00000000000000

$T('explain-special')

$T('sptag-boolean')

0 then 'checked="checked"' else ""#--> />

$T('sptag-entries')

SABnzbd-2.3.2/interfaces/Config/templates/config_switches.tmpl0000644000000000000000000011551313217005257022541 0ustar 00000000000000

$T('swtag-server')

$T('explain-load_balancing')
$T('explain-ssl_ciphers')
$T('readwiki') ${helpuri}advanced/ssl-ciphers
$T('explain-max_art_tries')
0 then 'checked="checked"' else ""#--> /> $T('explain-auto_disconnect')

$T('swtag-queue')

$T('explain-pre_script')
$T('minutes') $T('explain-propagation_delay')
0 then 'checked="checked"' else ""#--> /> $T('explain-top_only')
0 then 'checked="checked"' else ""#--> /> $T('explain-pre_check')
0 then 'checked="checked"' else ""#--> /> $T('explain-fail_hopeless_jobs')
$T('explain-no_dupes')
$T('explain-no_series_dupes')
0 then 'checked="checked"' else ""#--> /> $T('explain-series_propercheck')
$T('explain-pause_on_pwrar')
$T('explain-unwanted_extensions')
$T('explain-action_on_unwanted_extensions')
0 then 'checked="checked"' else ""#--> /> $T('explain-auto_sort')
0 then 'checked="checked"' else ""#--> /> $T('explain-direct_unpack').replace('. ', '.
')

$T('swtag-pp')

0 then 'checked="checked"' else ""#--> /> $T('explain-pause_on_post_processing')
0 then 'checked="checked"' else ""#--> /> $T('explain-enable_all_par').replace('. ', '.
')
$T('explain-par_option')
0 then 'checked="checked"' else ""#--> /> $T('explain-sfv_check')
0 then 'checked="checked"' else ""#--> /> $T('explain-safe_postproc')
0 then 'checked="checked"' else ""#--> /> $T('explain-enable_recursive')
0 then 'checked="checked"' else ""#--> /> $T('explain-flat_unpack')
0 then 'checked="checked"' else ""#--> /> $T('explain-script_can_fail')
0 then 'checked="checked"' else ""#--> /> $T('explain-new_nzb_on_failure')
"> /> $T('explain-nice')
"> /> $T('explain-ionice')
0 then 'checked="checked"' else ""#--> /> $T('explain-ignore_samples') $T('igsam-del').
0 then 'checked="checked"' else ""#--> /> $T('explain-enable_meta').replace('. ', '.
')
$T('explain-cleanup_list')
$T('explain-history_retention').replace('. ', '.
')

$T('swtag-naming')

0 then 'checked="checked"' else ""#--> /> $T('explain-folder_rename').replace('. ', '.
')
0 then 'checked="checked"' else ""#--> /> $T('explain-replace_spaces')
0 then 'checked="checked"' else ""#--> /> $T('explain-replace_dots')
0 then 'checked="checked"' else ""#--> /> $T('explain-sanitize_safe')

$T('swtag-quota')

$T('explain-quota_size')
$T('explain-quota_period')
$T('explain-quota_day')
0 then 'checked="checked"' else ""#--> /> $T('explain-quota_resume')

$T('swtag-indexing')

0 then 'checked="checked"' else ""#--> /> $T('explain-rating_enable').replace('. ', '.
')
$T('explain-rating_api_key')
0 then 'checked="checked"' else ""#--> /> $T('explain-rating_filter_enable')

0 then 'checked="checked"' else ""#--> /> 0 then 'checked="checked"' else ""#--> />

0 then 'checked="checked"' else ""#--> /> 0 then 'checked="checked"' else ""#--> />

0 then 'checked="checked"' else ""#--> />

$T('explain-rating_filter_keywords')

0 then 'checked="checked"' else ""#--> /> 0 then 'checked="checked"' else ""#--> />

0 then 'checked="checked"' else ""#--> /> 0 then 'checked="checked"' else ""#--> />

0 then 'checked="checked"' else ""#--> />

$T('explain-rating_filter_keywords')

SABnzbd-2.3.2/interfaces/Config/templates/main.tmpl0000644000000000000000000000027513217005257020305 0ustar 00000000000000/* This file was intentionally left blank and is only needed for 'skin' detection routine */ /* https://github.com/thezoggy/sabnzbd-uni_Config */ /* Updated Nov 2015 by Safihre for 1.0.x */SABnzbd-2.3.2/interfaces/Config/templates/_inc_footer_uc.tmpl0000644000000000000000000000343313217005257022335 0ustar 00000000000000

$T('restarting-sab')
...
SABnzbd-2.3.2/interfaces/Config/templates/_inc_header_uc.tmpl0000644000000000000000000002426613217005257022276 0ustar 00000000000000#if $pane == "Config"# #set global $root = '../'# #else# #set global $root = '../../'# #end if# SABnzbd $T('menu-config') #if $pane != "Config" then "-" else ""# #if $pane == "General" then $T('cmenu-general') else ""# #if $pane == "Folders" then $T('cmenu-folders') else ""# #if $pane == "Switches" then $T('cmenu-switches') else ""# #if $pane == "Servers" then $T('cmenu-servers') else ""# #if $pane == "Scheduling" then $T('cmenu-scheduling') else ""# #if $pane == "Email" then $T('cmenu-notif') else ""# #if $pane == "Categories" then $T('cmenu-cat') else ""# #if $pane == "Sorting" then $T('cmenu-sorting') else ""# #if $pane == "Special" then $T('cmenu-special') else ""# #if $pane == "RSS" then $T('cmenu-rss') else ""#
#include $webdir + "/staticcfg/images/logo-small.svg"#
  • $T('cmenu-general')
  • $T('cmenu-folders')
  • $T('cmenu-servers')
  • $T('cmenu-cat')
  • $T('cmenu-switches')
  • $T('cmenu-sorting')
  • $T('cmenu-notif')
  • $T('cmenu-scheduling')
  • $T('cmenu-rss')
  • $T('cmenu-special')
  • $T('menu-help')
SABnzbd-2.3.2/interfaces/Config/templates/login/main.tmpl0000644000000000000000000000637613217005257021425 0ustar 00000000000000 SABnzbd - $T('login')
$error
SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/bootstrap/css/bootstrap.min.css0000644000000000000000000045171313217005257026557 0ustar 00000000000000/*! * Bootstrap v3.3.6 (http://getbootstrap.com) * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}} @font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAFuAAA8AAAAAsVwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABWAAAABwAAAAcbSqX3EdERUYAAAF0AAAAHwAAACABRAAET1MvMgAAAZQAAABFAAAAYGe5a4ljbWFwAAAB3AAAAsAAAAZy2q3jgWN2dCAAAAScAAAABAAAAAQAKAL4Z2FzcAAABKAAAAAIAAAACP//AANnbHlmAAAEqAAATRcAAJSkfV3Cb2hlYWQAAFHAAAAANAAAADYFTS/YaGhlYQAAUfQAAAAcAAAAJApEBBFobXR4AABSEAAAAU8AAAN00scgYGxvY2EAAFNgAAACJwAAAjBv+5XObWF4cAAAVYgAAAAgAAAAIAFqANhuYW1lAABVqAAAAZ4AAAOisyygm3Bvc3QAAFdIAAAELQAACtG6o+U1d2ViZgAAW3gAAAAGAAAABsMYVFAAAAABAAAAAMw9os8AAAAA0HaBdQAAAADQdnOXeNpjYGRgYOADYgkGEGBiYGRgZBQDkixgHgMABUgASgB42mNgZulmnMDAysDCzMN0gYGBIQpCMy5hMGLaAeQDpRCACYkd6h3ux+DAoPD/P/OB/wJAdSIM1UBhRiQlCgyMADGWCwwAAAB42u2UP2hTQRzHf5ekaVPExv6JjW3fvTQ0sa3QLA5xylBLgyBx0gzSWEUaXbIoBBQyCQGHLqXUqYNdtIIgIg5FHJxEtwqtpbnfaV1E1KFaSvX5vVwGEbW6OPngk8/vvXfv7pt3v4SImojIDw6BViKxRgIVBaZwVdSv+xvXA+Iuzqcog2cOkkvDNE8Lbqs74k64i+5Sf3u8Z2AnIRLbyVCyTflVSEXVoEqrrMqrgiqqsqqqWQ5xlAc5zWOc5TwXucxVnuE5HdQhHdFRHdNJndZZndeFLc/zsKJLQ/WV6BcrCdWkwspVKZVROaw0qUqqoqZZcJhdTnGGxznHBS5xhad5VhNWCuturBTXKZ3RObuS98pb9c57k6ql9rp2v1as5deb1r6s9q1GV2IrHSt73T631424YXzjgPwqt+Rn+VG+lRvyirwsS/KCPCfPytPypDwhj8mjctRZd9acF86y89x55jxxHjkPnXstXfbt/pNjj/nwXW+cHa6/SYvZ7yEwbDYazDcIgoUGzY3h2HtqgUcs1AFPWKgTXrRQF7xkoQhRf7uF9hPFeyzUTTSwY6EoUUJY6AC8bSGMS4Ys1Au3WaiPSGGsMtkdGH2rzJgYHAaYjxIwQqtB1CnYkEZ9BM6ALOpROAfyqI/DBQudgidBETXuqRIooz4DV0AV9UV4GsyivkTEyMMmw1UYGdhkuAYjA5sMGMvIwCbDDRgZeAz1TXgcmDy3YeRhk+cOjCxsMjyAkYFNhscwMrDJ8BQ2886gXoaRhedQvyTSkDZ7uA6HLLQBI5vGntAbGHugTc53cMxC7+E4SKL+ACOzNpk3YWTWJid+iRo5NXIKM3fBItAPW55FdJLY3FeHBDr90606JCIU9Jk+Ms3/Y/8L8jUq3y79bJ/0/+ROoP4v9v/4/mj+i7HBXUd0/elU6IHfHt8Aj9EPGAAoAvgAAAAB//8AAnjaxb0JfBvVtTA+dxaN1hltI1m2ZVuSJVneLVlSHCdy9oTEWchqtrBEJRAgCYEsQNhC2EsbWmpI2dqkQBoSYgKlpaQthVL0yusrpW77aEubfq/ly+ujvJampSTW5Dvnzmi1E+jr//3+Xmbu3Llz77nnbuece865DMu0MAy5jGtiOEZkOp8lTNeUwyLP/DH+rEH41ZTDHAtB5lkOowWMPiwayNiUwwTjE46AI5xwhFrINPXYn/7ENY0dbWHfZAiTZbL8ID/InAd5xz2NpIH4STpDGonHIJNE3OP1KG4ISaSNeBuITAyRLgIxoiEUhFAnmUpEiXSRSGqAQEw0kuyFUIb0k2gnGSApyBFi0il2SI5YLGb5MdFjXCey4mNHzQ7WwLGEdZiPPgYR64we8THZHAt+wnT84D/x8YTpGPgheKH4CMEDVF9xBOIeP3EbQgGH29BGgpGkIxCMTCW9qUTA0Zsir+QUP1mt+P2KusevwIO6Bx/Iaj8/OD5O0VNrZW2EsqZBWbO1skRiEKE0DdlKKaSVO5VAuRpqk8VQJAqY7ydxaK44YJvrO2EWjOoDBoFYzQbDNkON+UbiKoRkywMWWf1j4bEY2iIY1AeMgvmEz/kVo9v4FSc/aMZMrFbjl4zWLL0+Y5FlyzNlEVYDudJohg8gPUP7kcB/mn+G6cd+5PV4Q72dXCgocWJADBgUuDTwiXiGSyZo14HOEQ2lE6k0XDIEusexDzZOMXwt1Dutz+tqmxTvlskNWXXUQIbhaurum9GrePqm9Yaeabjkiqf+bUvzDOvb2Y1E+EX2DnemcTP/zLcuu7xjQXdAtjR0Lo5n4/Hs/GtntMlysHt+29NXbH6se//WbFcyu+r28H0MwzI30DYeYTLMXIA2EG8QlHpAsyS0EfEToR0a3utIxFPJ3kiIHCCrZ66b0e2xEmL1dM9YN/MwS5p01N5jMX/BLKt/1R83l0LyC29M6+iYxo/UNg/EF7c2WyyW5tYl8WnhWg2/hyySbD5UhnDyS7OcU0dnrFw+DfGdI7v4QfYIIzOMq9hFtY55gmvC7jZ2FK7sEdrn6IXBuucYhjsGdQ8z0yEbWkkczjjsE5hNAIZrPx2zOLZDmKNXcXtg7EMqidAEEWg+SJCBBNwxvxJfc/bZa+KKf+xoKZybnq5vaqpPTye7CiF+ZFjxZ8/7Qij0hfOG/cowPA1rT1l4ymWnrKmxxqfErTVrpgwPlz1kC+Oy8NMDz6c+IO38K/x0xkPnLW8Kx6qGAoQdL+TD9V9rb+/ctn//trxz8dUrZrD/zk/ferF0cNt1BzctmX2FZPXt/jnFCQNz4Ah/iKllGiCMs1w5Lkg0kiEwj6VTXCDKsX9rMpnvIj9pcDecXAIXMnqn2dTUbN6w0XQ9ue6FV/nnXCH7S3lPWGltVcLsH75ub3ab7A8M28caNrIeOr3o5Q0yFsYL80xaa0EY/UEczV7icUMY5pnelAkmUAXmHYjvFWFGxuqlSaow3OM+/iYY7/l/hVELF4EjRqNR/bvRbOY+DUGzGR/Oh3EqmE/ugIQQguGt/eMYz/+L0cimjeZfQDI3phXMbMQsqH+CjwVz/hf4idHovgVmB8gLvjbicDcC/NypP536E/9N/puMibExdohBmNwyiaZdJGoigos7GpF222xrfnZhML/7Z+ylaqP63Hr+m7bdUkQ6/2cXqdfmvwixY+s2ksXFeXcE+iX0Z+Iow76DBNgjJ7TOdUK18iPsPflfQD+DPsZG2Aj9VmKMMJ4fYRrhIaxhTDR0Elh2vA6h/AE6xUb29mj3sjmL72petXjejPy+oel60M99tFduCI59N3221xe7apOvxs6aHs7vab1IqY2tv7q2xsHeHGml/cV06u/8S/xTjJ+JYc0bWEX0ukW6YmIbGkJRMdjJ9mYIH5QIdJF4hvRGyK7cC7ctImQRcUET99fGXOoft35GYLMQu+g2smnkgZUrH8AL/9Si217IssJ916nv14ZrJrvdxLkQvrvtBcjgPC0NXOicO8Qf4mcxPqh3hgUw3DDfdvLJXngg7N3dN2zbPJSaed3OfZnMU7dvmznp3C3bruO+Nmue0LFsy7S+6265+fCKFYdvvuW6vmlblnUI8xCXp37CrOZv4B9gauDBlYp7adcUXB5DNCwYImlXOJJKkAdvExXxVvKEYnCo+3eIskP9qrrfIYs71CccBjfXRC52udTHHdaP1A1ui/VvH1otbrLrpNXBsGX5B89QghDyimlvNB2KfkxZ5C9/em3+d1+d//IfFp2+2Oxn/s+9n/79p39S3s8idN6g0yZObwJOgKUpNB3GyU0Ls0PbRzIRq4lcarLKOJBkLRzJQD4j2090XrbA7DW8K3jNF5hlGS5e4V2D17zgss4T20egOJte5iD0bReM9yjTxnQxCRj3c5kFzGJmGbNKmwGw39IJDJcXJZGMkaAB4jyJAKw0jt5IAuIE+A+U3cVAZZrq9zhDyBrU8oosuxcGNTzCKJfla7JjNVmuSb/+tuzN2H+X4vlB+PpdfMXXmuVsNiub1T34SFbjYw5itEvVi0K0Nt9pNJUMI7SLGRhf2xipfCYf8z5OdlGKayOucFeVPeS/dbo3lBrbSMmwUiQN5/ed7g0Ds1s17IuZC5kNzM3MZ6EWCa0DtekdJfAxz+R/OX28sND7yRMTBcf++s8mQCQWHya4qBv/ufeMoWyslPA9DtMxUknxkH/yfTnm2CMYzs+Cq3r7PxY/MXomrvTEsRpfEGHa+WN8E1AHjElb7d06ddA7oK/+5Mdsv9EtPms0jv0Z5kf1FqPxWdFtfFr0kHfgDX0Y+5PRSG7RUj0tQr7rmfX8DH4G5W28kKeJLtmQsQkuwMP1pk16EV4sl7vrMJATfyUWo/GwEco4rh4XFQgaiUX9qxZHrMQqKnz/c2d8b9TysYrAuXpP/Rf/Gr8b1qwwc5a+euLa6S6sneNXToG2XrEJi4R5SGs8Sq2S3d97bsfCRaTdaLwKClRHt37mkudvXbjwVrLhuYeGhh56bvfQkHpk2CwvwClqgWwuBfndC3c8dwmstj81KkagcUgbfPY8Zje0W/82VPWJHmSq6pP8hPWpotc/EexDOK3qU+wngPhOCiO9MJRm8TJefjelrzoKnG2Bn+1NCUmPE4gHFmBN9jrTigRIpsACrc9Gstg58ULkp9467+Gf/eFnD5/31lNrt2967dhrm7bzI+VT5m+fzKhvf2MzpICEm79Bopkn07lt1762adNr127LwVqQLdJ5+lpQDcvHPQtVY5knhYrK6q8/JsiP6EuhGZdFdaNszjvpqvc+PI0CdjN0AXsFOC3ZfALDJwr4q2Xq+GF+GNbsxUg5NLLIEXi8otcDQcUts0D8eQ1iVDRAMBTsYiNdRIxE09EIBJO9A2xqgERTaW86BUFn0OD2xFO97FAgFhF6OoQ7prYt4XwSeUgQHiJyDbeke9IdQntciLQ1FlJMaYcUNvZBg+FB1ubjlnRNvl3o6IEU2w7fdNPhm/hh+FLysUu6++DLHkOkrSHYEjH0tEPe7WdD3uyDgvAgK/m4szFFR7ch0toUgBTdWHr7EpaWru6+6dmbbnqWEbV2EtxAsXiZAPTtGPSbHsotI2leoM8TePEqgSQprs7AGFf8kuOkPdZPXGb55POAW1d/jLST9v5YflasP6v/CO7+GNAPC2BMZWmsOjp2NNbfHwMCJD+LPVL+D/OYlWEEI/9jpPddOFkB5d1GSuKZYggmCCd7JUxD7EXAzxyirYnNDLdDZoFdx14kivkvGc3579Jm36reTTvDgBnaO6vzyQ6chQmlsMoIkIQ2+bBDWBud1Va4pcCn8CPqxlh/fgtG8IPaPH8C5wk6/nZDv69jurV5QhtwE0x2iqOsj9Mx8B9/0EaUdiPfOYYDCi/q9jhWRuupMDEU0+CtX0sDFxv07T/K5niBPqN9+tQjgEc31NGCXFeMcCEuQBIc/BK4CO78u7EPYvl3yaEfK3vcb6qP1R2tI7vUjVDDUdKubsSrNjYKY1qBEa2P50SJoaXiksIoLiCwnxS6EBuBde87botNfdEWwYvF/R0/u5yCqhGeEOR2ynSeyXjt6ka7neyye8kryBSWE52y+RBgogrXPZ8E1yIHoHIFUM+AbJhE7lbMtt8ApL+xmZW7PwbjAO0fAVoXQOuiSP/ksIVdFZ0aulsamKUzwPZ/NYDMJRBPCxsBqLzqHyneXF6Ej9HlIFo7+pg+jUb3unRmGpstGkm6etOuDBGA5wCMefp1gTHcdZlvPBXlOslvYTp1cd8UjYLVd/J5awNrIOKLnIt9MD9qdrKrWCvA6ALm3QV9VrsPm60Q7+RHJHP+2hqfugo/MvI2H/mqr4b9tFnKSRY1Y5Ek80Nm/WIhr1ikKnxGz9TWXrokf9xwujfvcOTtNTWnxd0F37Y2W79tteBqZ4G5qLCuomw+nSr28QESCRVLTyYKILGJOPfcnaIFOsewhRdvv+rWa/Wih0vlbX6Zb75T5C0qNKVFvH1QL/vazSWgC2s6oWXXIuUxQelKiJbowuJDQViatLmLijg9CQBMg8WiPgiw3LEeYRmm5f+XdnvkDnxLLjMLxtvX74C3OlwPQqx4xwIdpPx38LrlDphiyWUWHWKAzzxurS/xTo+P5wGFak62ap1PVFFN4v/y+xuR39WnIO7lsWfwgVsK17wxrs9K8ltIKuhkw7f/6dhK6gQokFKhWX3urrjk/rnI0pgfpGMeuQIUaEM7+GF5q2iMkCaMQwxxOzcvU0eXbsnS9XknXvP7Gtw5dwPXlFu2ecvSHEZgNDsU6x/GdXBYXyOQjzZReSedeEPY6nEv9gJR4oBQJtFO6Kd0fwC6BO4LNHDeBujB6dSNcUQC9zIv2LnAzGk99bUDrdFY+9yGFQtEo0GQPNv6vS2drj4+1jHbv3aJSMUWP+QTZrmbNTjU8wyG/iXNNpskybLcJ3CiTF5Ir+JYzmJwE0mSVhlxbtbmvweB3ulB6Til5UuUZydpgiFVeobhU0WaBqpJ198d+/XeNRTZ9/1OPfG7+2hwzd5W3D+hmyjsRcUg/+Cavb++Vh2ls3L7zT/etOnHNxeerv313vzLVqPai4nJv+K1FC6040/4udw7sAb3laSg0XCkAAs0npBO6VJabS4Elk/U+D4gTXW+j0wnrMlqNamq4tMIYB87tE10i0FR3LZNhJsb7/R561btmes8YBCRkhYNByRtKd55mqTas9FYhJnbRGHuOh3M4QTdgQSqmgRxuzGdSvZGcbMxNQGk5C3ebLjoXIOFM4l+WKHmLTJwRv9E8GWJ6dYvf/FmEyEGr+gyrr1p5zrgkz0Cw2j94Hv8Jdx7dIVegBSNtgsqGsRQEYiIBoXwD0LNvQ5d7s5Z00QzwNhqZA0b+tMG1tQq5nd84uq8R0zPvX35G8uRaze4jcOHzz0w1+Q2BIRvf6J6Kgatnrbiem+CFvAxfkrndzD9MFPP1GWTUHclpASUkCNAQkpCCcCgDSUDAhDZ+CuEkgn8J7i9nMA7pA4lISappxILKfAeSAbIcSDuN2bJcfZILqeO5rLs0MnngSHYRdrHjmaz7JEsEPw51ZqDJDmUIOZIe34WaQeegNsJn1qz8AIpT3yCjyEih/xELkuJ0lEMYTLVCiWpo5oYMleMH6USyYJcD+uOe+kWKpn1Qns34iyYDjkSLvgnZXcgVQNeqINXr48m3iS7cjm8tedyY0f1QvTnHHdsrKby/+SSbPY8/NH6vpl/Esq3Ae4ZU1HC44KFiI9o7CEgab/RqHbj7s5KAg06s39ZP/zxI/mVuF/TbTSy+3Fb8If9/cv7+wt91yy8RfP1QXtW5RzQn7qIiZyuFM5QfJ5E9uVnqT85TanFx0lkP3ukBAMprvsRyi/C8NAJL1xbIIirSvnSj4O5netb4JxmNANHPssHAcHMHsFRgEug816gDBeMbdfiuRcghqYcm0+Xxx/5IAEtN3fqFF3LzAXqwoT0PN0OVTNqxo8sxMkd5Ig6k79Zk7VxxX6gMLOZFQgvpW2RrMW1D0BDihaXQ9wVRoBxPLfpknmkeMtoB/qM9cRc9IqmMD2XUmdZ7GSRKPUZvChf8BoykriM2MnKYbOHX8R7cLdNCxSFFVQqoYswnlWtlFS2mNkhswVpZiQW1J/UKFfipHGlUkM6UKBhMz1istELIHJLMSctu3ugzfaVSOjKvUgc/THK4Sdg2Wscz69leKIkkrwuuWiOe9yGYKQXRumkC3qbRcMwrvhjNXgdZk3RxAUEhuSPvn3nnd++U/3vlVOmrJzCD8JLxV1OHRjrZifbcFDOuRNTGqdgQm1tSNJ2OcQ04YiEXuxtII1ECSQRoQGYioEsgCfchB4ghAtw7FfJre4WZ9hkVi9MtjuWqtdNDlpMrfEG9fOT6q21okg+e4As38MfGquNt7oUws6Ysarj1/efE+yst86YUVNvDdts3Pv5c8m/aP0C+f8/Qb+IMnGq09BgwN01oIOAnAdagI8mBSrqk1gxTDUBOtk2ousEtBH2z4Ir2d3f6k8PXXVlt2qN9RODxRuoJT/v27wm09jRYVc/e++iyx2tyzJb/n3J0htXP87eSsQaf2Ly0s6Zmxela88REy1cf4273mI3iXNJ7KxrZibOm9xm6rl4fqy/t27smU8tOfdW2ucBzg2UfmOIVyLIl3kpYlwphDISTXJXsctmiDtN7fNV6zelgxwnWxsVr83Aj/S5ki1jL/a0GC6+2L6Um+aoddlNFuj+bJ8mH/iaLh8I0/U51NspIEfq0dohwyFXKgm4NggwQ4rRhCOUFtxxo8XnitT4cnGfT93IS8FaT85XE3H5LMY4zIEPL1hw443wz+1UmhTJyJGxZzw+wsKkKZgUiVtKOKMEb2AKHTv61FNc01PQFwKnvsZ/9pPA4RKTASWahmh+8MxwzHxKy74IRn5LGRjsPUUwTu64UYNY38caqd7HKucZ/tHnODtENw/2UfHRMaq1UUPDJQ0OKkWCeet5fYOhII1VRz8+/Elg5j4Gxur3J8o2PJ4rg+2d08T/fwEzSVbyZ9XPro95T477lRKqUSRXQnauHNsISAl27oWi6Fv9z48JMv8r/aMMj8onCP/DuDZOuN+GPPr/+p7bx+7JlbYdppcNhzKU/1Px5aiaGDn/s1iGMaBcleKUo/v9rcxkZj7DBEKOfrayytXNLYiUdBY+pleQXdnscKlQcpzuWluxsieeyuXIK6SdxozitWyGOV3vOHHjguyCQ6fpIYy2JwvrQEF/Qa9Pdf/QqOSqCiE/EE1/XIVKTc2tzWbHnimrEd+Vyz311Ml3P0GVTj7PD5aDnsvCvH36alEaPMePcMegXs7x8igTu4B9v7G9vTHvhCu/kzIdx+BxC0ay9zRSvoS0F2lIxI+X7klU63I40gLQ3w5ep5na+SFnba3z5D64zv+QtM4n4ffG3tq4aNHGRfxgrXPMim+5487abL7xhdseIRn1KDl+7aINixdv0OD+JSPwKf5+xoP6aiTeQIDVlIhMcL1H5R9PYXvprs3fv2bO7MOplCmweuiq2JRZ1zz+9a/v2PH1Hfz9236w+ZrPXvWfAxlj4NLLHpq3c/PQ3uvmvbrjG7fe+o2y/cLdtE6VUlXi0ASb1VLUBVSUWSU4HdvAraTyS8xzM8NxvxFkXV6pUVRiJwcgC5zEeht4rwcp7ki0k41G0qlQhG1Vzlq8alEmnFi58caB5Q9vn988MLhqyVlHvLEWjtQFeupdiocF/tkkOGPW2ibWaBTkeZ/dvPWazXfOnnvL6jkRXpi85sFzZt+55ZptW3bl1cCCHZPD06MhySha7UFzjcjbp8fOecFCirzAG/yVjBX6OFIaadSjQq1nNhyIe8tVbaaSdHlXIWKacMeuZA1uxS95zILhyrxAdsXTL6m7kNQlx2P9uZf2qhufePFFbpI6/OU0WcP99RrCsrwseVot5mtytpf6Y0gm9sdeyKnPQ7onyK4nXlR/rg7H95M1upzu89DH6pgUcikoiihJ6NJKmRxV1x+MJiOA3YwhDRQrWU0u/0rvq0VYXnyCwsLeTJYBq3dAtJDavuzyoVpzZ99Z0+a0uoiFH/xcqgDR7rUFeOrUn6Cywb8ZeNMbhLV5ugP9l0zv9UN5b5mFkjzxUcpPJCn3V402pRxtJd2GrnLdhtVk9ZSZh9W91fCSH5B7ofxPiWL+j3D/uwhBRdyAyozeZwvQzs79soi+BKSnafLviZCcfrpBpLyimfLfTyJtbyruIQKD01tUwJyKEo/ybaxkSNFUMdMkhQoJyRBQFhnUkDQSXhTM+3NmY0EDM7ffLIjqWEGt8lCO6mLia3PukFnghosJD5p5SIho/VDkzQfLE+IrYoJXkD19pdP7OwG/voIUtagiWiZ4PAFTHHlTVhRZ7dYmPar+NJ+8JhmR6DFK5DV1foHoLNO/pHrvZfmWZ15RQlwvoVDKhCWNK3CCch9lfFBuAqUgpFSShmNaPj+i5++WZfKeViJfW5HnUakVL4UCNVkA4+ETfIqx4B5xSaP2L1yn0zn2ltPn4+OqZGmwwEVCaCSqG53ldtL1oLGAhdMLd09MpCCF6tD6ZnAZBY9hDaYsP0jzZ0j5ZjKsF4i1UmLuhbJMCnYJPt5VwFNvmZawXjEvLJqIH8STonZjq7BZ8gKgR20C9MDFqJAX1H64QW2NEup6qgzLP8cvppL/NNTOBTCJABOHeWoXzLhw4Wuy7gaBtjKr9kgKq8ZlRYBS32Lpxc8vIhpNDTfyNXWybMJbn2RyQ5EmWc2QF9wmSZ0KYCE+cPuYO6b15Uotj2Kd4MItLS7gtFbkTdrFND6pvEZqv5Yv7jXAus7Pg7avo7KDot50NX3CPkP+Kps8J9/3mGQIteY/LGPC+L7872SPR2br5fy8MtKBMHedGuM28/MZmPJMrGgi3Gb1S+Si1/L/zrZwO9XH1ce/z7ZQ1WSoY/+pMb5FT4ua0Wm+Jf/298nFmChEQ+Ti71est4mq9VYI6RsymoRJKYidElT2FGnDTZvqtfhGAFTbeqEw68GqtfmbVa/1IFO1/jdWr/8BDRRtQh9XNjubEm4aWVpVonpTGR7PVGc+KJNoBIWF7kYi4gUV3r1U6723i6TxUl3n3/tM27aZfKb7THiHW9VzFSwHJ05VfK6Ar7kaB0XgPPE0BSkSFKsBUpaLihEWoA9wBt8qirh2VSOkZwXEwyrxZ5jyt2rJmSo9gX7cg6jsEUGJU9z9xJPOEM3uQQxKgkh35DNATnVyrmJ3mbCNyIB/yox4wH1bg2DwN7q9kov4pFqny8oSm3RQbGgJ1QQTs6ZMLilOVYJ9v6Wha3HcJ9jddsXp9YhGUXLXt/qMDnvLpPNTXfNa60z5/yjXQOMq+lNmwh5egpYrdfZQZV9rI47xlRkuyTjpzsmCBSWNkAXVoK8sgYWqQJWbo1RLo6QH0YW6pxqfCnRgkd+RiFjUQUQ7poIaYoakgXxwFd9BuuI38H1xBxXSFb/pBDIKQFn7YB3dB36l7sG1FLaKiBdp1KxLvfswap/30lnVESgNnvjbUoT6w9N+Xoio0qcYOIM+heg940YimsucQVvli9NEcft2UZwGQwLuilj1fFr1i3NP94X+PE7Hpvtj6lBJfJ4R6NvWiaL6MgzWHxiN66DExa+dAdAbMYX6HVF8A+7rjEZIXAVbDe7PVI9rmN69JOLV1DOSvRPxWNPZBZf/Nf+Ny65BhYxxxV+77XJ2wfQ389/IQPgajXbwMsuAz/0IaQcXJavKbRqR2IqyZruXjVC2+hdee/5vdnYOedpmVtR3NGXldxSzDSIiBVpkGb9by89UpEPKrSLZmyFDzMab/wXl2CNe7s/qCtTvWgG5kpBmCBlSzDS/r8N4uwBwohRW63JTS1y32f0TQsPfXVGEHQrV8/NCfiOUVirYcBbIeA2+iF68rQIo3B/S628vYESr79ehzS7Q9LEL9UXmik9XVHb1yBO3Ngvt5935+k1efkV51mzzrM0LL3/20avnwMeKuWyOUZg2TasSqZ+KcZQiOn1Iu2Vh497ALUVZiCKt/gh6IvTIj1ZLRjWAkpHKOKovNwp00eqPROiAbiNEKieXwMLcXhVJ1/uzmLP4tfxaHR59cBdJVG1kTAgl9ze9QKUEQ946Hkb+okJ5JRDyf54Axur1D+WS49cLr0tTPEu7UmXrxcSr3XNvumv4yXzInXKH4F7Tc7p17Zt+t/qW2+93k063X7VW6lALxTY7i1nBXMxcxmzQbabxz+tJo+wijYaIGMNS8AoSMgAPt84DdHOoMPfjXhF+kuH1tZvuFQrRCN07xGcXRX9MYxYchDe5BcHj+Z4i+42WyPc8Xofi7bbZJN5nJLJ5qr6IqRtzqNlM17SpFsnkEyTWoABEjz4JXOQvzWYuwdnV5LNGOwTM5v9r4RpQ8ZXsYodks3o31JBlzbYtNotisnm22MxiwGFXam5oN1n0TA/hRvshvTSDwHff4nNzRo9Dum6PaJbMXzDz+x+Fkj4L4bFNBb1asqsgH7Dyh4DvbkPtf5yMDKzEwyoaESMSNS9P9gJVA3/RTlwoMwZvxECFWxIPNw9gi01nOHjP32esZTtmXHnxvZd8ZtakqQ7ekajbXetpNa6ocTVxJtY+uSe69OLz77zh5bDR3xjZMzUz6fxrz1nqrZGcHQHfPVefN+fiK86LeXj+Sc5lPKy+k/vCUI/DaLFYCWHr6nbXuILTIsb5imNKY/rCm28fSMxPhkN1XbNMNZGuqwOBhtTSxWuTk6bw0ZaG86b1hKddePOKuBvmiguYBn4T/yOqOyGRBt7bKUI1GjioBC8aUKwF7Q319UgcmtFGIzCJGBqwQij0ynDsfdFGc3TS3BlNfJ25xmzniMkpXXTPvCaD3ZaZvyzjmZdudBostmhb0ORZNN2sJBeed1HXkrUsywueQH+L0eCPxmsa5ZpgRJSDZ11yDv+jmbd86vxZfc1WcZJ3UkMq1BOOOVtvu/+pB+en186d3GTwWAw2jheaJs09/+LNfZft37DALyrNj1wABMuUKbODyTVnT/KYbJ3Tpq8IrNh92dkxOj5P/YpZx4/ycyiVcDYdn4JbEoKdQi9054iBKsygLW46FRGxAb0NPNCm8BSNCPjoKcj6EAus4SuP3rB+cV99/eTF6294dA8+TK6v74MHVpYNRt/I30e8QGTOOdfGWzzxcy+87a7bLjw37rHw1nPzp0KyyRSeZO+QQhInt3dYgvycjrPOv+T8s1rptaP84VeywdWX2T4ysr0/7TLIs6+x9zib56ye1dM9e/XsZmePY3NDs9zlnNVt4+WgHJbbz3Livg4P9WWgviOMm4kCRT6I8vw0NbUUEnFvOuFKoxQW1gTsvFirsF5pb7qTUCx4i7VmtToveaDxvK9uOaedVvPRpVOnNz0Q6bry7uiSdQ8t7Vy4JQKVS+XPplV2ts4bvCwZu+KzgITtxepaPRzWdpv74muvv6RO0SorX6cu/dqKn/XWnrtp/Zragz13DUCl5myiFW2Ycvb0PtsXnU+tx8pvLFbUspLX68mdegwmOif/NPDONajTGoUh6tU56HBJCTBASVvNUB5VIiKpc9kd7kludodSFz7xQbiOmMk5dOYk56gzL6uaf7N8a6MQOHm0ae6snZpFDfuT3/jdYzjzwkXXIVHoXNuCfQslQZqBZjTsoHMqrkE4jaYdgkGz2ATOgB3cPkSukD01DnV3ttb1wx+6arPqbkcNAHoFPzKUUQ+qL0k97pjbZv1I/egC9zTFbrrlFpNdmea+gIgfWW3wqkcis8ky5FAcRd1If5nNZrl2FFpungc8wpoCl1BpQV/ScS+zjlASyUTVv/AJ46gkJI4bHX4lTnloctxPZE1ckS3+jG2fKIjkQFyzuo8jvYQG1OrGvJPSTu/nSp9PHNTl4z5hK/8gtXVKF6gEKiglgcKiRlCESsQCV5QIlKWKpr34lt/wkSx/JCmP5/cBKQfl/5gd+rOS/+p91/+YCg5CXK2W4M9fu+/6xxX+vnelVuldIDCG0VQTpU9Dw4pRfei+6zWx0MLie0gPbyrkmRU7OwT16JGeyXLHqOLqAfVN1GPlBzWtFNzj0TRTCjogtP1NjIvu5habN5Aoa1k66wGpqriVetJgiGdwDZtKhnN0y4n9sXYnsqGmZfDSR15+5NLBlhoDaedEm7sxmpqRija6ZEEg2EAnTiAC8IrmFbGz1q08P9PSkjl/5bqzYqT9hMmptEXDgTqP3Wiye+sD4Wir4jCeoHbbp5hRfpB7BakUIppIlPCD30dR1GtslDz8OsqbXmejFC/v8wu5X2myq7SJ8Avzv9DFUJySf5uNvq4+Ti7W9D/OZrLChdwxmPNiBRqVjnpK/aGxRCDspVYKAW9AN1JANoo8wP4BJUlGqdgw6m1qPQ2QW3+OfU5/ieLS/NuKpDU3uf8bcAXyBal5jMR2NEAbPAZt0K3hvxHBEDlUxfIGcD+N2gNSNx36nfqlAYow0puatNpRz0e4W2oahKzQHsjf2c16ad/3t2KTtPobnX6D8C8pd0MDP+Kx7wnXqGGlLQcvikMErm6TmfsuxJXbSAxqNjOogJLQBLiKEHAE+JGTS3JoEhTrz8/CB+5YlupJ58aOat8Kv4JvregxwcU5Cp8GFAFm1FyOfto6GS2m1NGTS6CPNKkbsTdCBlnN9onMho55BX8IJZtEQ35lk+htwN5A0V3RCPoD/yXAcv6pAtbZczRUA64JmcUf4q7Q89ZHLeJVZ5D1Ps/t+0iCT3AHVtZC7JDCXfR7OSb/Xja5H3zQbZL1B+ULX1BMTEk3AseSpmnKEK4T9ekMIidUCRQFfcbj7z8gNLvzF7mbhQN8h6ZbRset+nQWdS/ZX3k7WpS8P9sfo0iGS64wV516pOhjI6TZ2dApgI5+LhxywYoWxKUrykKJsIoDsR4mSrCTg0egMPnLW/3Q5Nn8BZEuzqEI7HK3n0+zFmuO3TtWQ5WJoG9YqCD6Gc32SxnbnVPfsxvrFXK2dILl7bLthDp6glhcsfp4bYvbSmj/mQ94uBTw0E73x2jbNRCvC6VL6GCFDwU7eWQDcC5FY5s0slieRDwtAbRsbLXbaXAuu14e2OJw1dc6jQ3ZdY8v7rv2/BWZLqvFWVvvcmwZkK9f5jS4muO9yR5res4kfkRxhV03L1RfPOiPtYi8pd7jNEsOpyTwxpaY/yCZu/Amd5Or9uS3DYaeqVOhH7gZN/8I/wi1fEuLXvyNivibjuKvN+1Nc01HF/3h+ef/sOhox8MPd5SFucPjorQwXT+ytA8EmA5mamHNFDVhBI5pjZbQpugBNkO8MvRub8KVDKST1Wag7D3xlin1ZF7LFP/79nbvCXFOY+PUjrT7/otsPXXZ4exdPzuhZuL5LUXVAn7k7PbhG89uz3b41X01gbjP1xwlu5rrvvf9+pbs6E/Vu7Nk642/PYRaAiUBdrmO6CDTBLPQFA1ur0uXoBR1INDMkypKpoTqnSMx5GiEdTEaSHLs0Alvu/19/5QW9Rv1U1ridT22i+53pzumbs+XFFXYC++CGsTj5JUT/GCgRt3n78i2n71FHG4/u6X++9+raya7os3ZbDmgWfXun44e+u2NZKuGZ0HiF8M4TlMPR+EU6rPKRJ8wOU2RFUFLex3egEsz3YqEAq0cqhAAW19dBZIlVzR61tuIdTnpXH7l+uXrbjPUyep+8cl6aXKWhPHpDcXl9KiTWDNr4mBQc8Tq+NzK/OKSbsfl79o9G20R+brBXYvUg0rLHhtrc4TN81TTOWSZ0gL1ZVlOYH2ery/7XVUjFMbzYpg7UswcqJPQwBd0LKLabJ8IaCr2otcjSkIrGwootKECaUd4XH1+SdazRrfddkBU98t1htvWrbjqSqjaCguxrffM/5zDCpBALUycmajhd+R6ww4SWafuZ5eU+tPid4lgd3gt+b/Y9rQoZNmiXYPXyRHbRs8zX/f4WIFjWZJtUdSD55AP3xtXH+ZipC0EqdBGDA4CoYEU6gRLGPU11QhkLTBiEYPiqOeQgwTCl9aok1Qr5pFf71qEeNxjy/8F0GoqYPv75Yh9j3x4DuJ+uEzHRpAq2lMqb+qfTdiq6kGtzfOWsv0c7lSeMXDHBDe1MT+LUgx0Pg/p87u2UicdIvqQi8DkxhcUwUXCedMpb4NQjwY3npTmgsURJavLwCRyEcN2HfWsDVGfv/u9ZUWUx+PYFueUKwaNvbtu+Xps3eVWbN1GcgVrdMnWJ7WmJz9SD66EBidag0NF1Ukep0t5A7sFCWdhzvYwHv6L/BehXuHqfaBwBEU7hfVLcXvS4VQv+T/vaSIl7cbeMc7ekv9i8S3e1L5xxpvMGcu1EYPbKyCiijjGXcDKckm43PqU2qNWlXusZMiqF82cuVzolUHN9NNR0HZPxFPV9V0wLtvq+k4DqOwVWDlzuQLVdqFiP08cRX7aRlBVfR8cb55bWe5LExnlcsDp1vAP8Q9BucPMk1Ulh4GnN0SAdxcNHv3q9ohx1Ati4S/tkWjIDe3hQdkUGrGRaFBiUdiTSkI41UkMuuQHP+EaSQYlPQTFWJF03BNPpTu5KFAdkWgDukzsZKMG0Q1TAQQglScOaP/dsZ8+fP75D/9Uu5Gs3FY/2SxPld0DHOciXI9gqjcEidXjE+3BLosy0OcX3T7O5g65ROGyzQ2BZs7WbZVnO5ydLe32hMwTQ4wnnKXW6XW5LAa7oaXOIHoUl0FgLQLH2by8wSTWeAx2Y5PDazK3BqZbeJZwXGPaYhX87ZNszoDdaRxotXO1nNlpdvAPFWHDm8PqEE0sZxDEqGzxisFNnuCWetPcGrObN0p23tTZwMuRVodSV8+LTrOV3eRvzjQZiSjaLYS1WEJe0kNsJlZu9LFun7++wW4gRDRbaxw2nrOGm+xOj9cmtbp9ZqeTM1m8UXfQQCSTVSQox6pvtjot/FpHvIUjJovFEoYvHYV9C5Y/xN9OfcalvII37UEhTbTg/AQIaPb4Vz6j5u8/aViycMod/fkDcpu8QZbZoeBi/vbzP3XPsZvOubMtaPHkD9jt6+U2O7vqU/9C9SMvgrXpQNG/E0oJxun+CiElUa0IKQSUwERxOntKSV7ekcuh9VBZBBo3VUcB58ofKBHCwLyf9qFosz9Ibf8dGqwaBMjRig4SGOZ2UkWI7UiO9OfUPdxOYFApUZyfpY7mgEc5rtNGGk2H1lPhAk1Hp/VAMqQEHEUfEYkkUQq1JMdzsX7kklRrTrUi1wMcDjmu1YYfATj7Y+pGpPEBXuoQIj8rR9mgCl4C9yqmF7xnVWxGVniNqtpVmXBvQ6iwni5YQ8a1jYrXtc2J13HvgkvqWxuva1sbr+P2S5ceKGyBwDv2DbrToe1u6BkAJV7xnVLUaq0sJB8pFqcUIPi3yuwxi4JuLr+P30f3OkPQ72aO0xYo3/EsmO3QO5qEF8S0qQH0UsKXv0brnl9+8M7jF174+DsfvPOl1au/RL5/9DsbNnwHL2pHR1NTRxMZhJtHktOOxLxErPF6YlLvpC9YP73x+4ofw+3xVdrHcDE0dQQCmCRgvt9b35xINDf1CDcRSfJ+pYl+Sf8YcurfmXP5F/kj6J82jNsrkWiEuhVlgFfyNkB3S5MUzLhoNiwSCYcxQ7Ui4J0Xh7fmqRbaPa1tzujxkBRlsEHy0/OM4pYLPb7g9O6BQJN6l9zQ0OGyCaZz0vMTbHOzXfQ7a2tsterTcqxeInODoemdktw+1SbVhKwtW9ffe8VKadK0OVuC3bWzyKm5LeddsWTeorWyY9IMtUFutdu5g+Rn533qkocdvLs2HmhU75br/MmWtD8zA3OP2t1ea636jEzqYxJZGAwFiDEd61oTsrRuW3/3pYNi3bS+Rd+GjOfVpAPNd6y64Gsz1GaZleWIPoYL/v9mTeQBENVEguiF1aC4YeXxFETw6QyPfn0m9g8IrMFAvKM1EI11DARnbqibHk/Iojy5rSdgCyZi06y8sS024PeuO4MfwQ5Y9yKRZCqyYaF30vzeHlmUprR21tR0t0yz8KZY66zWuGvxVQB/36kP+K38t2Hu6NQ9SFJfw0AdpqPEK2qTMpf2VCqJwqPoJezTL824b8akoL+x03nhh+oNo5e77psxg9Q5LzebIKD+fsY34f2MtB9fk9v5b8PT6tYrgv4kRPwd0q9z3gdJSJ0653KjCYPwCaR5aUY63eW48O/kdo33yxX9wCiMv2QTrk8eGSI6Ag6moG9t2P/F7GRNlDjl0gw7pJ5aOXXqyqn8SENnXBmbSwUYLyqJjv3UmY1nKr4t80no0faXsaIEiF/BRaIBnItSce4OUif7W6Vm9T9H1X9Vj71BEm+RdmIJQST/ZfVdudUvh9S/qqNvqT98g9SQ3lHibZY0mRVHooyDN/FHmTgzjdozKw28NwQ0hwN6BCoPKaEk3YtKwNhwRLXuk076CGoZNXDQcRwZvreTZY9EZi+d0s4+ztv8iei04JQl6ZbDD2eHV7X4uHuFVfPrOmcs6m6Kr7hssr+1VZFcEZ/PdJkn1hOs8SXS/NFFgqt94PIZzZ3tdaL6Q5vo6piSzdy737pwsX1VyxUrF15iJ4uNkq+rbyg1Z+O8VsNC1UmcvORPRfxtPrfRwL2p/oA1eZp6Z/aGffoewaXcA/xBlKlQLfhQL/oPgBGP3qsA7IQS8qDVNswHKRSheDUvA3Q7MZoRcJMxlEygujn1QdyzfPfq3dEp/bXh5e5YXW2Ngfvza0ZF6UgFL/E0fTq4LBlvTE2qb/KuuzYSXVnjTfM1osvqMHVbm9950quIZlbqaL6YP7jk3kUtA0GnX2nvq53f3WoSsvEdDRnULgo2fN7lNZJgI8/VWi33c3bBZnGY05+dm+3qc7fNmj4YGKLj2nfqFP+g7jdDlxEV5XsJQZP6hYrS1l0VQr4c69Xueixp90gnZPmE5OF22j+SYEWHlZ0K/Hgsh/Ztsbh6h2DNRlvv6jJh9XaJaHCZDiUDKNTMkvb8vsqCyf3ZNdSmO0fa0Y4baJTtpbKzuVzeeSI7fCKr2Z0WypapnXJ4gnoWy3PoUIlIQ1TXdqhQJIXp9Wx5fYdpeWh2TY5D+YVyKd0jw3iumwi/BC3cEy4o83QlZnW79MrCgCjbhWXBlRZVVZZv4rIKpXC01HFlHdHLoeWVl6UVc/J5uGm6CViW5mulYMk+HqNYr0AyUPivLg2oMs2MPqtuhHyRyiwvNJej1Br+fcLyoAyu8D9B7bgmzUqfFobF5nKnK4+t8MPJkI/xHUNWk117jugWF+xazTAALQn6+UE9lhoI5ApGA/iuJOsrlNP28SVVuBVajXmircLel46w2bJS1Q0Ft0KDuikDFL/3pYrid1Q4FvofwRIo4R9h2ftSwc6jHAMqLcCql8YPHtlzGoByNXYN6v8hXnRaOhUvx0sVLCexwupGDR4NOYC7PePa5keIPACnuAdD7dEadRuTIiS6Lb7uskb381My5yjzF8lGCjBRqdwrWJCagfB3yCy7XT1i92hbcZ5Ci1FJkgYMDf6n+jspIsHFjJrTOdzSMuOa9DbDcj/nH9N9bIoGVgzHPWIQuFuYtaMRaq8eCKI0gEF6lPOZjBz3EEvaaxwSUT9U/8JbJZPJJLBLolH1La/RbF9AbC8JJjv/mMnssKjLRBJyqj9QXxNko0Ux/X79epfiXkm6fmKwF/en1HLc6LxloXWKvGa5rVCVL83VuiPcDEX/K5pTXOxHfx6HHB0t2FI0qI2rCZFTrvPWU67zVuS/kTsLnc7IKhFg30e4FOkqNSfH5PtkmUy6Cpiv/36k2sbqCeCFNa+URpoY0sZoYmCgCr3qgZz6s8I0gP1bYiR+D79H56NOz0EVWCTy2/fffvSCCx59W7uRV9995eqrX8GLesOXNm360iZ+T/El3uZqL+FyzSZ8XxpTiI/G0nkT4zznFZ0t4ipMz5v4q9ssqbdKUZt6u82knPCrt6PZwsnn0XySVnyPR1ZXAn72yx48bWJsu7apnI3Hy8bygUK5Js32qcytapqgmn95uexccj205vGgJ+euOeG2SORmKZr/qKzcx9SFctMJdwMUFZDJITs7dnOp1EKZCxg304Cevyfya+vlKqv6aXK1qIj3imL+L6hL+yvUlFfE0VKZ7E8gBY3M/8VoJCFgizH1W6VyC76nH6b7jiibYVxUmVIEspry/LgZIlCeP11Z4zs/AwvVwtGFEut5S1JY4lfyT0N/evOLo+rUEgjcqc9IkGpQbv3iW7Co5b+KgjvpzYdH85PLcc4X21ouwEGl/S4qnUAvoSlXUUhR1eKr2VWFTB+GMl6FsiQsVD1R3urlAAIoSn7JQkmiVVCHSpCwDH/qPepXQ0Db77CJOAImohB+RPWr31ev5g/kE+zTa4lbvZo8xdWPffQu9yJTPCNB66s+zXoJt/0L6hSoCuBIoK8fnBGG87OoRckJpLqyWe4YbpGi50g0+3I3UD85Oa0fzubfoXxPLbW3FDWzigmyJeM0tQkax7PqTy80+UxfUHPlBZIRVNQ+v0xRm8REKPoLmNr0+Uo48v9GFbXPKylqQ2IKm00QddgyWGMROCTxdLB9nCY8P7j2DjlsV/+mfr0C0r/NkeXbbpPlOTBBwT0mVz1zx9S/wJecBF9Wgv3p032iP2v4VSgfgW2G+HUEdEXU6iq4CtpLJfIN9XQG8dwa1VoO8XC2SrPDDyCOQptXgbcPvlAgBfxBoGwftQKeKFrNTASPt3pGGqDt/QRasn2kri+H6L80MJRsmVYJrAKyDItpJUy3/15WYIJqcJ9Q5N/LFJ4c3dc1URpWl9hW6mu50MUIelg4ucTPf15zs5DFo1c0VSp1tKB9jkwIyuM45kb+IP8gHed+6jO3v0KbIknzLy636E8KPTdCuUpB0wLo9JKnAO6pv0vS31EtBha/fJemkgLVVnd8KCk4qBTpQ5m7FbifBKrPJcq0pZAFVG/XbOFz+Tcq2MLrcmV28Nmi/OHskh82bau0k8eWCaPijQPWQ5lUvslwVCfHkXBMIehqUgtDNLeauH1huvZTbYmw+luPjyWoNGEuxRLR7LK5fSyXFUyK7PURQv2v8D3XOt2NJ6liBbmPGOsakw1kbeOs+31Wm5qpH+iJWSzqdPr2O7zc2TmtnrzCig6bBd/vgQmzOlz0STWIlmZEQfupogOZFHUZ7EkUnMn0RrpIMqAgHRJAOjIJ3yGw1I/MAp9q9S3Q/clADNm1wEeO+xbwg5OIYHZLY3ehG5lJk2xhco+6JWybpEVz2wrR6hZyD0QXZbeDVB+onmlimpkWprdAs4WEZDSQppsDlcdCBJJESIYFuAtUnC4GIF2C3Uu2Kv7L1bdz6FxtqxpG4TqQOqOUNAJ2HLvPWA2GgDy4O4vaDrtyl6P+1fAll+SyFcQ28GHqh7fvvf37udylf0fNwhzgz87Y+cf5x9GnF6ygHu18sAbipWeF0YPBgp2GaKeQduxxdEr3SgbH1kvH7tvqSLhedomOvZyts2dw8acu3dY/f+ucuMtCuP/e4zC4XnH3OLZ8ZuxTWxy8dJfU5dhDeKPSlJy5pn/+7u3XrJhmr9C5CuleGflGQocKnlAUaRKp0BAHV0ZwUt9VCqk6zYOgRIuMfePJzdmBdpPJ7/6B23+f+sp9NMDZevovvfYHG5dGPISQq1DojqNckchVrCcCYz/Q0hI0m3NKDRfkgsrnamo+p0CAq1FyvC3a3Nak/s5VX282x9Ufy3E39VAx6o7LpCvO2wK+ch9jNqpJCutcIOooKnYWtDK8gTRVYygRQfwgzKM5+jP2jOZdx3r32Py7rQUPOzAnoRs95NvRAR0qLGU11Taqu1bUYSzMcWjMEir067JQQHfIrLBHsrgv00/Wavd8HRLMEEYFSW3HCSNQehnrHztKqHcDyo4VfZ6gPKCR+gufwA8GegxUEo4A+gd0BASHiH6jYMLIsUdQJTs/C641KN4oCHWolCMLlMfIdtWKScjx7SM5LD9HnfmhrGI0S139UWfUnxgOXdJFW+AMcGjKr6eHAttHF5sUoeArYKDcxMSYcKA/xUDhPiEOEAPafSIUFArN0r24ynI91EPARDXvIDYyvqZaWeroBOUABQA/E+DXC7PWafDLQY2oiwpUEyj4RQtVlUp1GrM7In2p2A7VuiOW6otMiGOo5Mrp05ejVuTy6dNX/k/7mybZQ0nUmfrbx3U4KueDnlHm5wdh8FFeKnoaKKh/TK18StOPhwG9Xo5mqXAxvw/79YQwwDR+nAKQQ4izVXioB84qcppWB7IqjU45z4CE17OvF1Dw+oTFqxtz8dxwtogBnF9MjIl/in+K8s3hM9laIn0TiCbTAXL0T798bPXqx36p3chrv0O+GC9Xaj48Ecv8U8UEeBvUEsDlTepiU5OvlpeNGvpnKF0RvUooWhIjnx6GeBapXCQYTw9DNg6/OC3gZjp76oNTj9Kz6Jqobxb9NDqc08vcKReOpcsQV2K8InXFaXW3aI6Ofr1k48rp7CX7rx+v1UKPsfvzQU0Kc83i2VdILmd2/yX55zT9luN2+Cu4nKfwPcK/CvDVU+pHh8+LaldIf1fA5h3ndT6Fln9/W/9Ce1vndfvJtnPVO2xhm3qbafHVCN1X363UXHq9xuVD8OSD29Z8pZ5cZrern9cAdGW/uib/ud+VK0L9a42r6C90kL8KzxwLQw9NkIQJL0ASU8M+VG0KsUdgdvpgP/6NqqP0/gHZFUfGEijZLHpiIgvV5/Bltrj8Qd7XQd5p4P+7tJo30NMO6VGBwahSPMYiaaBYoLY6uEnciyhhh1Z/vvacG/rjpsvnpzs0B1Id6fmX8119l88XnOxe/uGrzzHcdu7UtY3+2vmXN5zUyj3ZcPl8p1sZSs6/nGXtwrV7Ka0XZdz83fwjjINpZWYw85lL8BRK4nGyIir2RiOsEyipuEcIakpGjWgBjLiHWOgj0Yi34gW1kKPxHt2Na5q+lwg1RdRSpFDNzosb44YJXnAfoEOpZW//6u1lhYA6leevezbI26zNHO811M2dc5HFxpk4i1jPC0s21/BWW5DnPQbn2X1WK43/aM2n18DfSoybbNHijFpamzXI31eRibGUOxSu/lT96YZlq1Yt20DaSBuG6knw2eusHs5EPBfNmVvHKdaQzcDfz9ZsXmLDWGXy2U5OsYSsIn8CS12jQIyD12KKqZrLPy7mSPdICmd6WGHG8NDZkkHuE4h9TU8FpmUO/VjC/EinToFyoNDz2p9XD6g78WgQdPG7Z3R0T/Z5dTM9lsL8Ktek7szl2L+gQwGgwkZHc2g5Su7NvVqwGy2Ua4KSXUwt1X4PaM5paaEu6jQ5zVFyNabxvUksVt2T/4VeamYPlLtffdQsk+2sUTY/zDXl/05W53/Bz9UK3p7LjapZ2ZxOm+UlZXrL3HHGqO8+wVroDaCTTnTxitMxmiAAYQzVJQH+nj3oIHnPaN6Zq6sNSLjBl8tKgVr2mj/9CWi9dnKca8rBQBsd5R1tzVlgrl5pbnPw6kZclCr2CHxMnHohLz+3KRQokzALyeIKFU1TNCiayJdoHvDYe7K6mZLm8S3uJ9dojuaJ62/qN/tjQxnSnhnKPw+LNrLi8ZKyJ3x1YhiI1aNAtP6NzCGzYv3DmaGh/LvQZnt0evgIhTFV0kE/PYxAnOHhCQUZdCWY5JWJwMzlAGl1mpNbDU7yyGnhRMILsYhH3VRAijrPcBU8/Cj1Y9NY6cnGVW0CjTLaz7E3epvaT/LtTV72Rs+0WVVmd0dz/MGTI5F0OsIviaqDlbbO5X6xT3PeXbXHRtf/z+fdka+eKPr8KF7IF4vBsT9MFPuPJMBTBMq9hQxXelQ+bewnf18ap4Ib+mSMrtDU5zqlD8QANa5MBGh/OwOvSDfcV2d66mfEWsbGWmIz6nsyZDWQSmqmxDneYyvjHPmRXHZxeueyRGLZzvRioKnGto9nIPkibAJA16adcOZRQr1iAP3bUyBR7T4RgAWTKxhkCYFwshq+7iV9r0whk50cmRcTg4fy5x4OmmNkHndIA2+YuMbmE9dwGYB4KFTsvnDE6Ah47r/fE3AYI+oXADpkdlENcZ8OZEEf8FFGZNxMs6ZLpG3SUFLL7Q2kcFU/A/Jsw+vWDa/7emewLaoeibaF1B9qUNnuqWK3+UfXYVL1v/omD15xxeDkPnXTOKSVcCbDGtOu0YQNpGAP7U1HU58UrqGu8xIbHtkQ3LVhb7Dx46ET3Ffcm1q0YcOizNmf3bC3VjWfAcpSv3MyTlgJ23FHQgmgvk+gk8pL0mcCDOn08MDAQlf+/SlTZ1z12fnqntOhbOTL9/ZdevbAPN+yby1f/uUtC/ixm8ZBo59LTXEW060hGrTDplNprWd58fwB/b/E27BdS/s7U+rGVCeQ46nzaw9QccnmZerGZZs3Yw9aVHt+Kh6HN4ti6lxIhT/wahnZtWwzlY9QHQ2c79C+dxzvVDKy8GqKWQERO9YAKbpsDUTLdWV5dE8PVPjvj9pqw7ah/PFVtkit7aj6G5xY9mfJrCz1j1e0BcnPol4UjtrCdbahIVtd2HaURujnFJR8CuOuUUfhrGhgKKgjCYNSvCc1WKlEp8wHUaAYynFNyzZn+2MnYv36dbMDBTonl/T/ma5IKAyEGz+4eRnVtaX6tss2o34u8mWorFtuFgm4A6qK/yp/gLEBVat5WnPDdKA574ubuFJ/IUfZ/Y2Nt6mN+ZNNTSTaeI56gKwkXerTe9DDHUw8/H35FY3nNN7GGuBKWhrV9ep+0k1WjNWVaHkW1yA+QHWNu8rtBw2a5YXuE40rs7/GA+j09V3hA98yRnFPOGr8ltGlsFdD/7tRce3LH6Trcneuiy7K7J3khKu+3qUaXPWaX7T6/Kfj9BX2eZq2XAcZT79u1ClJzUtHUqfqSMWBcZS43Ena0cUGLgpkKxB1QM+0Fxz10wgg6r5rltnFpH05pepUq3Y2HfYqeKRntmUFNz+XmcOs1H31U6cC6RTVLfCg7RNBF1UF2/wBgu0fFQtPEU1sSg3VcNsR7dWq3af87tUFn1l3ltXpaJxpNvtcZkH2WmMst3JqRpxUH+WC0E1qOGtP66s1MYv+VLu8/XFXvV/ZbunYYBeVN64ls0ur6NzpV9xzlmQwB5qC4Tq70WC0tk8dWJXeHvkD0h9zJOM0vD86/1NJMaIAolctvlByferCsqOKDKceOfUu1PsmoFCamV5mCrMUOCi6V6FJosMF22AcrKJgQDVhfYh6tepp/lYgvnCEAbJQ1L0rOpajEmRcasMiPfxhgGoVo4rwreQpV6fUJHH2e8fa1s2c13Apl1b89a58ozdoap2sjgLN9uISl7P1DrulyeIkt0zr6JjWocoPOZsaXPb6jtqBblsgsaRre2xHi4nELm0MhG1+x1SXwLpFi53b+aHRYo/IrbZtuWAKu5cSEXfybnnmUCaXGTpQr0xK2O2WWY76f+nAjNVf7nCZHU5XqIkTnpt6VtvsFlPXg1031g/VRdpkkyVpD7jnmax88QwDvg/66NnMRdRXTcGTmQc3cuINwN5IQqi0yzb+YFVHuVqI5s4ADfg5oE4ybDLd28mFSFmYvRoomsWXEdLU2Wl3GJy93ZNb/d5gqmNaqJZSO1l6PVRy0nZIj/45EetjLguh1rLqR+SK0hO6NrsqcNX8zoUdjQYDJ7tb4os6+i+Y0qpY2AWlnLRDWdGFTfGY1gV0zNAtJ7pdo24se0D88AwLY/gZmE9iuP4V5v7CSR/RThaHLh+UeBkXwU6BC7lGOevK65udTv+tS/PfW7qj3ljTcj3b9OkbV85t8xsMj7Ddj7DGpthZKwKPvso/c/1K9aLE12fMWLV1y1D9ua8lyJdWXr/bG+noCFutf/mLILe39ITUV4igr3876fpX5g2zeB52sWnIL4fXHlgeUzOx5QfIvJQyrKQE9wHUqVq+PEaOrz0wVvNbJZVSfsuMzxN4l9PkedFzw9V5Dj+nzpgoT4ZxCxJfC5RWLc74YVHxKlExCYt0JAOMatREhHBSCAtSfod6x6Ls8HCWECLwXZ9nd5Dz1T24JUdWs6fU3++fcnT49Qe+kBs+wdsMZgPXMp3U5S958snPP/EE7bvkOPCuTUDTUQ/UzirLhML9yPahoe1D5Fj5jWsaoveyP00PehdUAHk/seDVWsvDWXXXsyn/4wfpXc2V3/Qxli3jl/5hj/83avSCfpTNxOEKLmTjxOEKuxgNlsQn0xgct724mhynupNW1Ph6o3RYS3/+2TJrzLlkFz+ip3qCHKf6eqW02QJLjBYuuj4sobhCWqa/YHGEHpcnumuWSOhxeaL7sOakNR6vvmo+YcfFA8UFXEPZf9UjyudIOyNwx/i90DdsujS/FX2UAwvWSVK4NxaMhAGw3oowp/uc8CTi7D2rBgZWwb/60faR7SPsEbjkXy4G0XaqhXPwe2cePjxjxuHD6ssQuR1fq6PF0E+o2t1nePTn8TUmxz/A3crMoCc7egESuoTHYc7mYdg6etORoOhR7BBGD+qJopELrl4S6cJNRtEAsLP/OdvnJq0Wo0GolY2Et9VFB2Kf+4bZvVyxfOMz3WdFfSIryj6DwWghre7aQbdiDrkTL3A3vNDuDpk93HqXwam+bWmUJZfNn5ozKV5Pmmq8PF/jVY+2Tlk2M2RzSXKjmbQ4RZcQavEYrN/9rlXwtIQqzxQNMzPPfHYLvuPoO9TbT8bpGw5CQPGd+SyX/Cyf0Vxjd2R9NmsunnXYa8xGHzn+sSfM5J0y0DZEXWWxkXjcR75KBLNLHi7XvX2G8VOrf4Ykg0AMdBESIpo7MgAfyakA6rkqpI6UjNs0px7cMV+D5BF49Tez1VGnYmq0WIijp985m4Sn2gJR9b07riPPFo97OYbUZbxJCpot7H/lpZBicglCPN7WOfJkcHqc3ElWqvvz/1E6bIQrG+tz6WkM1SM9FBTR7FSs8KyBBytSmNEoquJNFN5EQyTiCrnKDx1h58yxCepPHU5nxGoxEQeeOZi2m80DxNxncVhr6BmEfUarxejw+WSiHhWk19bSY7aKR5MsteblJpfTLtjimBouXsm3d3djjYM+wEW0El9dM/ueVRWIsXwe43R7SgbVZqrnqoJ1X/kuF7pcgf8duv4q6vayV5U9zMV91GxO59UUjW8rHV6u799WzKMT7umRCXbYUKM+foaCcwgaoqZUtmodV3p+X7akb4dnU9B9La38RPFUG2SCC90tVA4XwEFhyOpZZrUCsgWYHsczLFBBVGNtstoN1bw0Z+O4fYIbvZVt4EUcJEKOhHeincWqONw+q6w5Go+WGOSR7LhKV+KBqbBPpfUvOf9QqkpDyVhBeyyZQGMsdA5FBUqvFMtUyGq9vjnsAJU4UcrxldP1CCaofyDkSAifoP5QwWx+SyUGxp75BzGAvtG7uQ38LehlyEQMeh0TeE6Bm7tYdXqdkt0uOb3kfYlNwmOdDyacOq/qlFo1v+PTmTi3E/glC9W11b34A22zmLzvb231Q0L2Bgg60OTW4YdstO+YOJnO38TtpH7zy9ymokWyA79qlVSn38HtpFlImFnhu3b4boNWXklOXV0Iwo7lQ1hrZyPFcwtjwFP7iEKSHSSJw509kh8kj6pr+H1jR7km9vcvqN9657vffefkv+fKxge1X+7RdjYUPIESN7gTvRkB/RMYtEkaVkdHApmdBPpnKmz0n1xSWFOyVIuLrinZwpoCRe6kyiVZoHX088F+UX4+WKS4iBTP0IWxGtZgOdMaV4KTayqHQF/VihBwTbgDXTCmKoOBJeNhwJMzEVjtjIFLuU38fPR7hqNG1JS7g/qRCuy3vmQ3W9Vu8qbVbP+SzazGRJH83MzP90Ck2m31mMjP8TiLn5uwD2Ugr2PFvPQjB5BnSJvQxGQZZEB+LopqzGzDbMmbkAPkZVJjeO5FzOSBKCgJze2ZS4Gemc9twrwY6u9H61iUQTcRvtdT9RW3tRxAWwFs2tcuJRnI6xjmBdWjbgFNRHMHiF1uHYBfUR/ut5Ug2jXAaT96+9RH/FToRwIzGbKmVJ1AZQnoabSB1yyIg7ByAridHApPMjyw0OiV6RjSbCuzwLAvFizBliWJua1tsuAgvNPbmljYbpt8lkWam7b3XZiOiKJskMOtmfScnsbPW208knwjuXrXK4Q1iKIgNyYXXDVT9C2Ye/78GQ5BEEXfFdde2RwauOysdJNL5AzCy84ard/nGAVN8alecnFdgu5Gbd5DJTL+hHZK0vApVy3OfU8XTSJg1TlssivsPYUlIqvn66PzrVTymCc4wgF6SDNR0pDf+9Gp+VnsUH5WtpHYsuhOaey8zdwLN47V8MTbm78g687+P3cx6tcAeNpjYGRgYGBk8s0/zBIfz2/zlUGeZQNQhOFCWfF0GP0/8P8c1jusIkAuBwMTSBQAYwQM6HjaY2BkYGAV+d8KJgP/XWG9wwAUQQGLAYqPBl942n1TvUoDQRCe1VM8kWARjNrZGIurBAsRBIuA2vkAFsJiKTYW4guIjT5ARMgTxCLoA1hcb5OgDyGHrY7f7M65e8fpLF++2W/nZ2eTmGfaIJi5I0qGDlZZcD51QzTTJirZPAI9JIwVA+wT8L5nOdMaV0AuMJ+icRHq8of6LSD18fzq8ds7xjpwBnQiSI9V5QVl6NwPvgM15NXn/AtWZyj3W0HjEXitOc/dIdbetPdFTZ+P6t+X7xU0/k6GJtOe1/B3arN0/pmz1J4UZc+D6ExwjD7vioeGd5HvhvU+R+DZcGZ6YBPNfAi0G97iBPwFXqph2cW8+D7kjMfwtinHb6kLb6Wygk3cZytSEoptGrlScdHtLPeri1JKueACMZfU1ViJG1Sq5E43dIt7SZZFl1zuRhb/GOs44xFVDbrJzB5tYs35OmaXTrEmkv0DajnMWQB42mNgYNCCwk0MLxheMPrhgUuY2JiUmOqY2pjWMD1hdmPOY+5hPsLCwWLEksSyiOUOawzrLrYiti/sCuxJ7Kc45DiSOPZxmnG2cG7jvMelweXDNYXrEbcBdxf3KR4OngheLd443g18fHwZfFv4NfiX8T8TEBIIEZggsEpQS7BMcJsQl5CFUI3QAWEp4RLhCyJaIldEbURXiJ4RYxEzE0sQ2yD2TzxIfJkEk4SeRJbENIkNEg8k/klqSGZITpE8InlL8p2UmVSG1A6pb9Jx0ltkjGSmyDySlZF1kc2RnSK7R/aZnJ5cmdwB+ST5SwpuCvsUjRTLFHcoOShNU9qhzKespGyhXKV8SPmBCpOKgUqcyjSVR6omqgmqe9RE1OrUnqkHqO9R/6FholGgsUZzgeYZLTUtL60WbS7tKh0OnQydXTpvdGV0O3S/6Gnopekt0ruhz6fvpl+nv0n/h4GdQYvBJUMhwwTDdYYvjFSM4oxmGd0zVjK2M84w3mYiYZJgssLkkqmO6TzTF2Z2ZjVmd8ylzP3MJ5lfsRCwcLJoszhhyWXpZdlhecZKxirHapbVPesF1ndsJGwCbBbZ/LA1sn1jZ2XXY3fFXsM+z36V/S8HD4cGh2OOTI51ThJOK5zeOUs4OzmXOS9wPuUi4JLgss7lm2uU6zY3NrcSty1u39zN3Mvct7l/8xDzMPLw88jyaPM44ynkaeEZ59niucqLyUvPKwgAn3OqOQAAAQAAARcApwARAAAAAAACAAAAAQABAAAAQAAuAAAAAHjarZK9TgJBEMf/d6CRaAyRhMLqCgsbL4ciglTGRPEjSiSKlnLycXJ86CEniU/hM9jYWPgIFkYfwd6nsDD+d1mBIIUx3mZnfzs3MzszuwDCeIYG8UUwQxmAFgxxPeeuyxrmcaNYxzTuFAewi0fFQSTxqXgM11pC8TgS2oPiCUS1d8Uh8ofiSczpYcVT5LjiCPlY8Qui+ncOr7D02y6/BTCrP/m+b5bdTrPi2I26Z9qNGtbRQBMdXMJBGRW0YOCecxEWYoiTCvxrYBunqHPdoX2bLOyrMKlZg8thDETw5K7Itci1TXlGy0124QRZZLDFU/exhxztMozlosTpMH6ZPge0L+OKGnFKjJ4WRwppHPL0PP3SI2P9jLQwFOu3GRhDfkeyDo//G7IHgzllZQxLdquvrdCyBVvat3seJlYo06gxapUxhU2JWnFygR03sSxnEkvcpf5Y5eibGq315TDp7fKWm8zbUVl71Aqq/ZtNnlkWmLnQtno9ycvXYbA6W2pF3aKfCayyC0Ja7Fr/PW70/HO4YM0OKxFvzf0C1MyPjwAAeNpt1VWUU2cYRuHsgxenQt1d8/3JOUnqAyR1d/cCLQVKO22pu7tQd3d3d3d3d3cXmGzumrWy3pWLs/NdPDMpZaWu1783l1Lpf14MnfzO6FbqVupfGkD30iR60JNe9KYP09CXfvRnAAMZxGCGMG3pW6ZjemZgKDMyEzMzC7MyG7MzB3MyF3MzD/MyH/OzAAuyEAuzCIuyGIuzBGWCRIUqOQU16jRYkqVYmmVYluVYng6GMZwRNGmxAiuyEiuzCquyGquzBmuyFmuzDuuyHuuzARuyERuzCZuyGZuzBVuyFVuzDduyHdszklGMZgd2ZAw7MZZxjGdnJrALu9LJbuzOHkxkT/Zib/ZhX/Zjfw7gQA7iYA7hUA7jcI7gSI7iaI7hWI7jeE7gRE7iZE5hEqdyGqdzBmdyFmdzDudyHudzARdyERdzCZdyGZdzBVdyFVdzDddyHddzAzdyEzdzC7dyG7dzB3dyF3dzD/dyH/fzAA/yEA/zCI/yGI/zBE/yFE/zDM/yHM/zAi/yEi/zCq/yGq/zBm/yFm/zDu/yHu/zAR/yER/zCZ/yGZ/zBV/yFV/zDd/yHd/zAz/yEz/zC7/yG7/zB3/yF3/zD/9mpYwsy7pl3bMeWc+sV9Y765NNk/XN+mX9swHZwGxQNjgb0nPkmInjR0V7Uq/OsaPL5Y7ylE3l8tQNN7kVt+rmbuHW3LrbcDvam1rtzVvdm50TxrU/DBvRtZUY1rV5a3jXFn550Wo/XDNWK3dFmh7X9LimxzU9qulRTY9qelTTo5rlKLt2wk7YiaprL+yFvbAX9pK9ZC/ZS/aSvWQv2Uv2kr1kr2KvYq9ir2KvYq9ir2KvYq9ir2Kvaq9qr2qvaq9qr2qvaq9qr2qvai+3l9vL7eX2cnu5vdxebi+3l9sr7BV2CjuFncJOYaewU9gp7NTs1LyrZq9mr2avZq9mr2avZq9mr26vbq9ur26vbq9ur26vbq9ur26vYa9hr2GvYa9hr2GvYa/R7oXuQ/eh+2j/UU7e3C3cqc/V3fYdof/Qf+g/9B/6D/2H/kP/of/Qf+g/9B/6D/2H/kP/of/Qf+g/9B/6D/2H/kP/of/Qf+g/9B/6D/2H/kP/of/Qf+g/9B/6D92H7kP3ofvQfeg+dB+6D92H7kP3ofvQfRT29B/6D/2H/kP/of/Qf+g/9B/6D/2H/kP/of/Qf+g/9B/6D/2H/kP/of/Qf+g/9B/6D/2H/kP/of/Qf+g/9B/6j6nuG3Ya7U5q/0hN3nCTW3Grbu4Wrs/rP+k/6T/pP+k/6T/pP+k+6T7pPek86TzpPOk86TzpOuk66TrpOuk66TrpOlWmPu/36zrpOuk66TrpOuk66TrpOvl/Pek76TvpO+k76TvpO+k76TvpO+k76TvpO7V9t+qtVs/OaOURU6bo6PgPt6rZbwAAAAABVFDDFwAA) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')} .glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} /** Changed by Safihre, Nov 2015 We include the icon-file directly into the CSS, this way we avoid errors when HTTPS is enabled **/SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/bootstrap/fonts/glyphicons-halflings-regular.eot0000644000000000000000000004723713217004753032105 0ustar 00000000000000NAMLP',(GLYPHICONS HalflingsRegularxVersion 1.009;PS 001.009;hotconv 1.0.70;makeotf.lib2.5.583298GLYPHICONS Halflings RegularBSGPMMF٣(uʌ<0DB/X N CC^ rmR2skPJ"5+glW*iW/E4#ԣU~fUDĹJ1/!/s7k(hN8od$yq19@-HGS"Fjؠ6C3&W51BaQaRU/{*=@dh$1Tۗnc+cA Zɀ@Qcal2>Km' CHMĬfBX,Ype U*Ҕz miO1nE. hx!aC XTV‹ R%|IHP5"bN=r/_R_ %҄uzҘ52ġP)F7SqF{nia@Ds;}9⬥?ź R{Tk;޵ǜU\NZQ-^s7f 0S3A _n`W7Ppi!g/_pZ-=ץ~WZ#/4 KF` z0| Dѵ&däIÏ;M{'omm I !wi9|H:ۧ{~qO, L]&J09/9&Y 蓰{;'3`e@vHyDZ$3Dx28 W Cx5xwB`$C$'ElyhԀ DJ $(pQAA܉A@'$ hp0V0 `se$4$"t2=f4A{Tk0|rH`L&sh]A<`R'!1N;_t3# V *veF`E O${)W=p:F`22ړC^.ćG<.pNe2ִ+Ysl:˼ ܫu5tu^86ȄTmyQ%u~%~1rҘawߚ^_ZZa0!N`. uqYB\ᨀ[e:@J'Eہ,3ubj@pfeW9( ޅ=lG7gj SM609OˑlBa݁ <Bՙ(VRApf^+g9qMt]تpEr@]@VkV ud^X R@?EY2]#Ǽ4JK'dPC|mmn#$+48u'e&[n[L%{BCDL:^!bƙ:&g3-3ub iLZڂWFSId6.k5Pl77UzT:NN.")['|U"AIvwptdk9嫫9nDmq7I|6Kbc]MBABȪ_JT q  6@Fhd`GT:M7'L,IhFP ~j $¡„ 3hA-S^چ-%qe~Qqln"i&Qe?FlK"As(3Y;"Let'RzM1 0{=) K%$C 9M4c EotjVGD)l8,\w !%$3t TBzҴ iUJ[xgdBr$!eq"J> )\~3(^ R€8#>bHG'7_ fӫcκtDoAA߃(qB<``VΫ֘*buP4v@+.Qԥ$V@C0 RܐP[z:XH#e s>?EWO>@I$|si ES)0A?9ab,@K̩o&Q% ϞLu+ +H|Ɛ?NK4CnPt 'OT.j5Ĵ8vw֜I&+`yScaO[#gQd[KI矗`ČLP # )27aTi@c\ސ 0nCpߖ運4͵x*RzYbT[\kUvHʈqp঄IIŗ) bB XPNtz 2 I== ;}bqjiކa#" >11Ap1POOuxQ Fϲ(h݄O'MDxLK$ȵh& 14SirHJPtDM;rM+ *ؗ5u2$f3K %ѳb (@,2f,~"7R;E;HX(42Z'Tۿ2J+^!#oY~4-׃GW*!A0&8f{`W=DP8'= R g}iP>#4EBRY^4eN8V,[BĨD#X],LBsNC> +o^x jC.4Ya_{eA2=r+9POA!! }YPJeGn%x1/}RgHa ^3- 5 |qSaWK{ 1al`I1 Qf_yyCZ)L3X] W6@DMT<.uGK8DsбWr\7Z\V"ISd>CUjeD 3MtWcPӉ6#3QnቩJ\7#磱`؀K lV6 &T ~l. @61`! ` wYk/a0A¹ԁYhdxk:fEao̟^<IwYgq7s[ -y1ع5aMKאRBYFq}8*Nt'.YbZvK (]&ɜ(ՙ2:0 oΏхPKiBH4UX,[$ 0mXش f50VR 8%ާDtUs`-BPzPsvI8z-t1DiB "˶YTJ .?07jLN[2tĮ̎ #6?E׻:ɞY;A&qSIR)ss 9*x0Bj)mHAhyЏhMm&4Ŋ4 gV&tYOCS0Yd7MvNj)wA(o "͢[ E`7ezď-Q]6+Bca@^I:һ=sSnc 6 OB4LGpBq/>O pwj A*@JC[h&3B Qbϩ8 :%f~v/lS00a"B8(f uGoǚgyt_y~͔ %mL !I$Xt0~ePz]Ug Н=_?.j#+`li BM5 őGp7a ֒%Y[UG9@\bDY{{ED0 $Q+FvC`ݨ3Q E\uC9![$l 6DoDgG*+X!%#Cq ?8ZUB)U@opgީZq89|uccAќW;@">Ph_9}.6V/O:3}ZS {:~ykcO6;OB=bV. Rk o ^GV= }oI"+ ]wFzϷ`<30h3]Rf859s`KM8 XUq<\ZOssM&j&  .%PBL~^Gˈ3pD:Z<\ǠiW̆"(:zX~0PG]8RQMNTqfW~!0R%Ց0xvGFy/F-wu/*+ \8@6c<L;c[º nr QS'oQuT{qҐ_ͿSdA*ð:m8Yuz2PB Hh`lkpLLh cEb6eۏҋ ?!>| *=VK@rx0G`%ryr[6Y37 f**n%9df11ޢځ^'] Rq.,^%l e#wWs56!=!q[ %Ԯ]5^:m5)?V b|u7fw,:Ye R% [ o gFAzFPx{dxíw8ٔ{{L> d2CLL,L,(mS$=|%֝lu& ą83 N Xx \VnJ[)Iw/鹻 |GźYDH*Sp60cJ2@W%Ѧc_^$#*:G6n>D;~`9hXB UJB_вˈ%w'$v|#T<68KMϑ-5U+'B ĪNbJOv'|+*Mk(d }C˱@q&aR%} !VЃs3w2a2awHz/Q0F ]~;ä NDP mK3xke_ S!V&=v_PL9؃Yi NU_)J69f*S  17F|BR$y,Ʊ.&=uqsODBR=ɳeؽɇBH 2lu'h7^#S)Xi2..Pe/@FK$](%|2Y1pC8tI11N//+\pjdWmI=߽YZxMЉP81/ JG^U ,Pd1O^ypql2h$jvI%]V .'[+WU8[D,߻-=[ O wE)3J&dقݶR¡S\. 5J$I&oHȳ~ lz> Ux/Hu;?Gt{?;TH L|F8}{p:2t͆aѧp65Y"LD.rVS_ k]n&Hz~9æ p $4ق'{&M\ΰч!qi (.h' B T|{I6cL.빍iI꫿\!;g`1 j%C o3*60E؎]t.-%0 YK_nft] *VFCtJT+\WZ8gF^ ޞf 5I=#6.@2z;W`B/ęQghjyJNAX3, K66ڲM0T@O{4kj|"ftџۄU<-a5b)^R8:ilKa6@!]buvΏ$ oUœ~:.Lte JξP l$S[z~Rq39钺9Q/m"%ʤ7 5MKL鑧"IߏG XTގXLFݧV jp^/Mgۻ{w *9Oʈ<"aAq.M2@mp^'wߕmkxO8 $[&|YZy`2_|%r/J?QṈl3ÞKE$wvCh a@U1M%0?1* $GZ{!|ʿ$ە-٪Ev;͓:`Bl˸쌧ɬoQ0&,F?^s,ch˕$Ecl0w`⏺ň@/r^l8cT3k@JݔuP&ʪNdJjTKi *uX{tj~ɡ}i\BKenȵ|N u#]@lCZ$iPa㸩t04y20 s֪,Au!QBϖ^@Vsɑ\Za7쾉ш6-TrU u~1HJ(<αbRԖqi J?eG *jVħ ":Y);-Fd!HG~ux cb6m)&;0dU?8X~12ۼtIx5{(z '[ŃkZЅi,b1̇`(mHNeK/ [(#QGduT^m%!(7KgP=hϕkɐU+.[eC"GDΨ<*Ř 9&܂?)\<&Ŏ5 LJu@Y,냲ھ_w0^17p޻*>D8_)$UźR!jOF>{ t,-bP,m`D"/zA ͔إQZG&U]xejxLwv~=)@B6?!;53/ps@tOZS7ؙnlxZ?Zj a{6L41 2Qi&֥l]o=7ļ ofЖr MEV@H/aD٦HlK5)ŒZ OE3IG'г;D'zl(E$.ٜ-W R'\w+)w3꺾 @%R).~9;].šg+)%ȝk҉^NW>b1z:soD K2w[|>9vWMFu`axchիU`*ʆe]OV'6xd?H]_rA+zdFH ʋ<ǴkUsFzaH9-gvb=L/E).x9j%B)$AB t b.bAEZRbH(Jya9Wj0fF'Xz $DQ6q` o i={#4FYH@J3 3i~tYТhkHP17YD"pĦ;'16fpu>FoDQin̒- @P# hj ނŀfC 7°T5HVXpklĭ]yXr)?ͺBNJ B#9e&&_0=pZ6h) ̗a b=(p);.N,W^ *hԺCm}E7i6aIvͲxp*Ac#4N&`)ĉHWey7jloEh_n3 jp?4p2WE'kT_ &!ȖjVlHӻ_kɚʳaY s@[G"bYLܫXi Cq8&zVaY{#I@2m!d[1 AƢnKeם/>dmuX:xʷ\pNl+H+ctSǶC[~3e}6 \,Ʉ|Yݧv]'|&M2 ddsx-((76aXm=ӊQ<$Q†\ qiH阇i'i$"{S*VwF/tfQCWUZ{S;Nx}H&* 9׸qU1 a`(M-aG}n̽0 pmcn ɘ_\l} 9FvHþkJZNO mZQҤ aSf )QC+2 d[ H"t* c*bڢq,#S#u'Ҭ:4asCDMF|ɸm_1L]Y\*X>tgDd@&[)8;<{8<+VG\H^aae-4sJA \ hM[\`#pD5Z97g;BWmqTXX%0v&]E 4]FIJ&S_4R0D+meY gO+M{03v'ͅft:;ر Nn\ǔ^,)1laBZZ[  ZSUYh߆wS\/*?zQЋ`X4gr[CWG.Y0Q|RԃE[wy),ш$NK@c/b -#ZI G$ƗtmH#)XwPZAD|S ofTH)>M1b 7ɆSuq jK4[s xL Ǣ]5 !M!AdƧN><:ǻZ(8)e /W| bDDŃtT7rur0Ң`ܴh5 5S}4hrvalc!ZjB]xDbTxzYS6_)op>#@PS*bS\q ƋxYfQ><" Y6IEr_7Ұ VH!IrEL6!Nq"'daqMvA% v n.;A/2ʲa8D$GWv#̏ 9k'o؟o@ (]gk+}/ (nqK(f Ɵиp23YwpDdGq2$}KӯA"E&Ntg'Nes!Ю4qo}쿝S,ojr/s TMT&Qf\12h'&ctN'Tx7]2 ;G ʅ|T++:%/ 1T  ˀ<4͔˗ ,0~!WO' :suҦن(^ﮎ )7fmlҹ1ūtZh L0 6X"J҂ 49 ֩B}ԭ``Ӓ #Jn_F H|$OK=œi17o-Hqp[ɫ%%:Ɉi3۠G CLL4S:dBj|pYSDP>pv5KLe{t0yEND$*;z5NBIgn.N|׶nRaSZJcH mXek;_ 6,yb0#ZA e|wG U1lLD7ÄVqt[xuEQULPBlZSh.1Q0Uٱ8Rip;{H#GON!?t>Q |pkq!gT,j2sǍ4툊tjnƛ/IOE!ˋnF4M&1x$ew+vS  bm]e%8 P !s_06)Q2JB [t9'Ԝ,[fÆג]BB@r&Bs|Q gOC1J D&LJiC`A^#X8tH?daĖTSTaH0@U)^e}Jb7%ܔ%:ƿ@M+ysqL Y00ÔGD >ĩAW 2I:F 32ʠq:6S]K"g[ ϑHB5VEqLJX{CB!PIq9Llxʪ7>֤]@!@9H!pə$ ?)܎l/"́+@`}}:\ 8zQgS+򒤿C}R:HUF\Xg/AZ%c1wlETwX ZNhyf2D ø&vLq47z\iJyJ-kN3 -sJ5)V0N0d\ӛd0d-E[mf\UmxCR<(`ѕp4^!hQ `!l ~ƙ:JɠlW9˸ZXB=l)`jeVJUG!s1?Ƽ3Ê.}bIa6ʕ t?SxZJ'p i,.R2T`5-R BxrWH JPe#Bb|-[PEh‹(5Sfr/]IƊ dE#OS39ӻ]eۮɹ.9_beM9b#e(- 0Ra9"U,%~X܀z۽{'6[@t[W%* .d'vR {h!AedCE}x=E[|B$7J* B- ,=k7[_-I J5e̶{ ( ;WMw`~pAz 8f))(@ Īم<.a%N n@bz>%T*?lgbd<ĵw9Na8;<^*%y:tDҕZ<@0q4l\ 1`/$IJ ғsN);:A;)$ו Wwy%KrIv\bV\nd{6tv/~*O 7U>8rAC<jE-j牷xs)D1Ì/qp**̸$ّ,  Bȼpk MhpK7U]h&-$鎻Y;q6wzW˄֭AhD^R"s5fw +Q&/9ȂwNbz{Y> ]NEc,ߞ# BF:0/-EȾŒ׃F\I{tAZCORuk i)ytkdN&vA P{P'>xƆ`.%,;:Կ:aFoTQ}v#ףQk's~z5hMQʒY>CʍiUNF#J0uC8k! fv {E/IKIE> pyde ʾ=z:@7J|5g8x 3O 3H1؄F.yfzWIM j[.w%i?҆Uf|}@+[8k7CxSEOޯp$Q+:<]K3T-y[Nz;y-HZY^.M*'h8A.N2rLB 7:Or}CS˚S9Jq#WI}*8D!# g#Y>8` В ?a2H,^'?^nhOƒi<Ya2+6aFaMG-Gkè1TbL `*ـVX *xe§֊Z*c`VSbJU*6TK@zqPhg*ߔU(QU49L cM*TR!R,BȅE*C|TzpF@4*텰جXbL.T2y`Upb T,%@` #?@tGLŞS)ÿztϲFy׎ 14Lhfe(.)pK@\ Xe@TbvhD&0-IbD d@ZD1@ DyѧCN| 94Ӛ#Nc l;, `cX@(2$0 "@- $B@<$А8p7C b(@ PA@F 0tGORIJITySMW52\ToRKV0Ȏ( -$ !6wHGO r~e~/]V~/P~7SzKFv`;`9v# JBN,ӭ'`'`\LTApBs)r! ( i`SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/bootstrap/fonts/glyphicons-halflings-regular.svg0000644000000000000000000032430213217004753032104 0ustar 00000000000000 SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/bootstrap/fonts/glyphicons-halflings-regular.ttf0000644000000000000000000013053413217004753032104 0ustar 00000000000000pFFTMm*GDEFD OS/2gk8`cmapڭrcvt ( gaspglyf}]oheadM/6hhea D$hmtx `tlocao0maxpj name,post5 webfTPT=vuvs Z 2UKWN@ { , h, h@( + / _ "#%&&' ' )9IY`iy )9FIYiy !'9IY` * / _ "#%&&' ' 0@P`bp 0@HP`p !#0@P`fbߵiY!     |vpjdc]WQKED 5 *+  / / _ _  ""##%%&&&&' ' '' !& )009:@IDPYN``XbiYpyaku } )09@FHIPY`ipy !!#'09@IPY `` ((h ./<2<2/<2<23!%3#(@ (ddLL[27>32+&/#"&/.=/&6?#"&'&546?>;'.?654676X& j  j )"& j  j )L j )"& j  j )"& j LL#32!2#!+"&5!"&=463!46^^L^^p@LE32!2+!2++"&=!"&?>;5!"&?>;&'&6;22?69  x } x }  x } x v L   d    d  l d;2#4.#"!!!!32>53#"'.'#7367#73>76p<#4@9+820{dd 09B49@4#bkv$B dpd>uhi-K0! .O2d22dJtB+"0J+ku0wd/5dW%{L>G!2+!2++"&=!"&?>;5!"&?>;4632654&#^CjB0  0BjC x  x u x u@--@$?2O*$ $*P2@%d    d   BVT@L!2#!"&=46 %A+32!546;5467.=#"&=!54&'.467>=2cQQc22cQQc2A7 7AA7 7Ad[##[[##[dd76!' Pԇ $ op zy#%**%$ pdL #7!2"'&6&546 6'&4#!"&7622?62~   \l lL 7  &   l 2'7' & c_"fn &\`tfjpO32!546;! 22&&L%6.676.67646p'0SFO$WOHBXAO$WOHB"7Q)mr *`)nq&* )2"'#'".4>"2>4&ȶNN;)wdNNrVVVVNdy%:MNȶ[VVVdXD>.54>0{xuX6Cy>>xC8ZvxyDH-Sv@9yUUy9@vS-H^{62!2'%&7%&63 a o  ^{"62!2'%&7%&63#7'7#'JJN a o  d⋌&2##!"&=467%>="&=46X|>& f   f &>|.hK  ]  ]  Kh.| L#'+/37GKOSW!2#!"&54635)"3!2654&33535!3535!35!"3!2654&35!3535!35~  Ud  & sdd dd d  & d dd dL   ddd  ^ ddddddddddd  ^ dddddddddLL/?!2#!"&546)2#!"&546!2#!"&546)2#!"&5462pmppmpLpppp LL/?O_o32+"&=46!32+"&=46!32+"&=4632+"&=46!32+"&=46!32+"&=4632+"&=46!32+"&=46!32+"&=462LppL/?O_32+"&=46)2#!"&=4632+"&=46)2#!"&=4632+"&=46)2#!"&=462DDDLpp&,  62"'&4?622;;nnBB# "' "/&47 &4?62 62    ;    %I2"'#".4>"2>4&3232++"&=#"&=46;546ijMN,mwbMMoXXXX K  K K  KMbyl+MMijMXXX# K K  K K %52"'#".4>"2>4&!2#!"&=46ijMN,mwbMMoXXXXX^  Mbyl+MMijMXXX  -32+"&5465".5472>54&&dd[֛[ҧg|rr|p>ٸu֛[[u'>7xtrrtxd/?32+"&54632+"&54632+"&54632+"&=46  ޖ  ޖ  ޖ    ~ p     >     GO27'#"/&/&'7'&/&54?6?'6776?6"264X!)&1-=+PP08,2&+!)&1-<,P  P/:-1&+x~~~P09,1&+"(&1,=,QQ09-0&* !(&0-=,P~~~d!%)-1!2!2!5463!546!5#!"&53333333,);  ;),,;)D);dddddddd;)d KK d);ddd);;) dDDDD 62++"&5!+"&5#"&l`    j`  w  ? d3!#!"&5463#"&=X;),Rp);vLp02".4>"2>4&3232+"&546֛[[֛[[rrrr|2   [֛[[֛;rrr   2  ^  )#!3333))p,p,d/3232"'&6;4632#!"&546;2!546& & T2   2 >p  ^  12".4>"2>4&3232"'&6;46֛[[֛[[rrrr|  & [֛[[֛;rrr   12".4>"2>4&%++"&5#"&762֛[[֛[[rrrr   &[֛[[֛;rrr  9!2#!"&'&547>!";2;26?>;26'.    W & & W tW    >     '2".4>"2>4&&546֛[[֛[[rrrr[֛[[֛;rrr] $  (76#!"&?&#"2>53".4>32  mtrrr[֛[[u$  Lrrrtu֛[[֛[576#!"&?&#"#4>323#"'&5463!232>  ntr[u[u  h ntr$  Krtu֛[u֛[v h  Lr d/?O_o!2#!"&546!"3!2654&32+"&=463!2#!"&=4632+"&=463!2#!"&=4632+"&=463!2#!"&=4632+"&=463!2#!"&=46}    R 2  2   > 2  2   > 2  2   > 2  2   >   ~   R d 2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2 L#54&#!"#"3!2654&#!546;2uSRvd);;));;) SuvR;));;)X);dLL 732#462#".'.#"#"'&5>763276}2 d!C@1?*'),GUKx;(.9)-EgPL 3 0[;P$ 97W W!1A2+"&54. +"&54>32+"&546!32+"&546ޣc 2  2 c*  `  ct  ,rr  ,tޣ 4  4  G9%6'%&+"&546;2762"/"/&4?'&4?62A   Xx"xx"xx"ww".   ^ x"xx"ww"xx"r/%6'%&+"&546;2%3"/.7654'&6?6A    `Z  HN.   ^ d  g~jb1K3#"/.7654&'&6?6%6'%&+"&546;2%3"/.7654'&6?6 D@  *o;7 *    `Z  HN iT "ZG !   ^ d  g~j  !%-;?CGKO3#!#!#3!##5!!!!#53#533!3533##5#535#5!!#53#53#53!5!ddpddX,,ddddD dddd,D,ddddd dd,dddX d,,d,,ddd dddddd,dddddd  #7#3#3#3#3#3!5!#53#53#53ddddddd,,dddd,Pdd[[[[[   "'463&"260V C;S;;S;V0 ;;T;;  ! "'463!"/ &"260V 08D;S;;S;V0 V08;;T;;d&!2&54&#!"3!2#!"&54?6,9K@  D@   K|@  @  J  L !2 46 >>CEU!"3!26?6'.#"#!"&/.+";26=463!2;2654&!"3!26/.6D N9  >SV N N      & X & l l- p  v       dL!)13232#!"&546;>35"264$2"&48]4$);;));;) '3]dϾV<?!(% _5,Ry:" *28 T2*BBW-ޑY". BB % Zd'2;#!5>54.'52%32654.+32654&+50;*7Xml0 ); !9uc>--Ni*S>vPR}^3:R.CuN7Y3(;  G)IsC3[:+ 1aJ);4ePZo!56764.'&'5mSB ,J   95(1(aaR@ 9%/#4.+!52>5#"#!#3'3#72 &2p"& 2KK}}KK} dd R ,১ !%/#4.+!52>5#"#!5!'7!5L2 &2p"& 2C১  vdd  ,}KK}}KKL/?!2#!"&=46!2#!"&=46!2#!"&=46!2#!"&=462X LLddddddddL/?!2#!"&=46!2#!"&=46!2#!"&=46!2#!"&=46DLDLLddddddddL/?5463!2#!"&5463!2#!"&5463!2#!"&5463!2#!"&Xp LddddddddL/?!2#!"&=46!2#!"&=46!2#!"&=46!2#!"&=462LLLLLddddddddL/?O_o32+"&=46)2#!"&=4632+"&=46)2#!"&=4632+"&=46)2#!"&=4632+"&=46)2#!"&=462ddA ddA ddA ddA LddddddddddddddddL#*:J!#;2+"&=46!2#!"&=465#535!2#!"&=46!2#!"&=46dddd ,XLdddd}KdKddddL#*:J32+"&=46#3!2#!"&=463#'7!2#!"&=46!2#!"&=462ddgdd /ȧ,XLddLdddK}}dddd!2#!"&546 K,,,,,,v,,,D,,L!2#!"&5467'2"&4,XJ*J%pNNpNL d>tNoOOo62.'&54>"264usFE66 !^Xm)!fhHuXyHÂ2".4>"֛[[֛[[Ktrr[֛[[֛oVrru5.54>6?6&'.'&76#&*IOWN>%3Vp}?T|J$?LWPI)(!1 )  HuwsuEG^F&:cYEvsxv!K:%A'# " A)Y l */7>%!2!"3!26=7#!"&546 7l l27);;));Ȼp87cs* s ;) );;)2cL6!#"3!2657#!"&546&'5&>75>^i4);;));ȹpS 9dTX .9I@F* L6;) );;)g  0!;bA4 L5!2!"3!26=7#!"&546 62"/&4?622^^  Ȫ   ȯ  ȭ   ȭ   L326'+"&546d0dLJJL#3266''+"&5462d00dLJJJJ3''&47660J*J36 &546.2   d32+"&546!32+"&546  dL#!"&5463!2L  346&5&5460d * ;O#72#"&5&5&5464646dd12N: 9  > =,L32+"&5&54646Rdd0L;;dH  #!"&762!2#!"&=46  *9HdduJ  u`((&;(J ' 7(a#aa32".4>#"#";;26=326=4&+54&֛[[֛[[}dd[֛[[֛dd2".4>!"3!26=4&֛[[֛[[E [֛[[֛~dd32".4>"'&"2?2?64/764/֛[[֛[[ xx  xx  xx  xx [֛[[֛ xx  xx  xx  xx  $2".4>'&"2764/&"֛[[֛[[Tw[֛[[֛1Uw;K2".4>";7>32";2>54.#";26=4&֛[[֛[[?2".4>#";26=4&#";#"3!26=4&+4&֛[[֛[[    KK  ^  K[֛[[֛V   2  2  2  /_3232++"&=.'#"&=46;>7546+"&=32+546;2>7#"&=46;. g  g g  g Df  fD Df  f g g  g g ͨ  fD Df  fD Df?2".4>"2>4&"/"/&4?'&4?62762֛[[֛[[rrrr@||@||@||@||[֛[[֛;rrrZ@||@||@||@||02".4>"2>4&"/&4?62762֛[[֛[[rrrrjjO[֛[[֛;rrr}jjO!2".4>"&32>54֛[[֛[[KtrAKihstr[֛[[֛;rtxiKA>rtsS6!2#!'&4' &F   &S &5!"&=463!46 &U & U ## ] #!+"&5!"&762   && ]32!2"'&63!46&# U & U # &] &5>746 ^$,[~UU & U #$DuMiqF +!2/"/&4?'&6!"&546762R,^j^!^j^^j^P,^j^IIgg+#!"&546762!2/"/&4?'&6j^^ ,^j^`j^,^^j^/2".4>#";2676&#";26=4&֛[[֛[[:#6#:1  [֛[[֛.   IUaho276?67632;2+"!#!54&+"&=46;2654?67>;26/.'&;26!"&5)#!  &0  =  2 pp 2  =   353  X  v  v !{,  2  ,ԯ  2 0y    r w  +I6.'&&&547>7>'.>7>&67>7>7>-BlabD8=3*U  :1'Ra\{%&=>8\tYR-!q[Fak[)ȕX1 "@&J<7_?3J5%#/D &/q!!6ROg58<'([@1%@_U2]rO.>7'&767>.'&'.'&>77>.'&>' '8GB    `H  >JS>H7 '+" NA 5M[`/Pg!;('2"&"IbYCe\D9$ 886#1%)*J7gG:    8G\au9hoK$]54<&"&5476&2>76&'&6?6&'&'.{nO9:On{{nO:9On{FZ  2Z__Z2  Z# %8-#,- "F-I\b\I*I\b\I--I\b\I*I\b\I9>||;7Es1$F^D10E^E$1u$/D0 "%,I';L!#7.54>327377>76&'&%7.5476&6?'&'.P[vY,9On{R=A &/l'PjR.Mv&  6QFZ  *HLh5)k|# %8- ,- "xatzbI\b\I-yRU4Zrnc1?1FrEs11) ]@ @] )1ES>L'+/37;?CGKOSW[_c3232!546;546;2!546#!"&5353353353353353533533533533535335335335335Rd22ddddddddddd|ddddddddd|ddddddddd2222pddddddddddddddddddddddddddddddw%7&=#!"&=46;3546'#"&=463!&=#'73546oXz#z*dXzdM*zL!2#!#"&546d);;)d);;L;));,;)X);dL ?32!546!32!546".5!2>&54=(LffL(, '6B6'p)IjV\>((>\VjI), +'%! !%'*L 'L'a'M 7 Maa'aQd_)!232"/&6;!%+!!"&5#"&?62**p&032!2#!!2+"&=!"&=#"&/#"&468^&d,!02**6%%+*2222 *L !53463!2!!P;),);DPdd);;)L 3463!2!!;),*:,P, pX);;)dDEk+32"/&6;#"&?62{**YDk&=!/&4?6!546X`)  )   !.#!"!"3!26=4&53353$`$-);;));;ddd-(d;)d);;)d);dddddL #12"&54%##"+"&'=454>;%".=4>7i**d]&/T7 " LRQ  )2( Jf,53232#"./.46;7>7'&6327"&)^Sz?vdjO9t\U>/ v?zS$2451 7F8%M)(  ()GM~ 1==7'''7'7'7'77 N괴N--N괴N-N--N괴N--N괴d!-=32!2+"&/#"&54?>335!7532+"&5462(<H(<,F=-7` 1dd>2vddQ,}Q,d-!2$'$(ddw} L 0<32#!+"&/&546;632+"&546!#35'!5X,<(<(21 `7-=|dd_dd22L!-d,Qv,Q($'$dd dԯ}wdO7G%6!2+#!"&5467!>;26&#!*.'&?'32+"&546dkn  T.TlnTj:d%8   VOddip &yLN(  % H YS(22S dO6F#!"&'#"&463!'&6?6*#!32!7%32+"&546n jUmlT.U  nJ   %&jPddO (SNLy& pd(Y aL7G2#!"&/&?>454&/!7%.!2#!"&=46ސNS( % p &y22SY( nTjkn  T.T8   Vd% dd-I!26=4&#!""&5&/&7>3!2766=467%'^ NLy& p  (S22(SYLddjTnlT.T  nk V   8%d%2".4>%&!"3!7%64֛[[֛[[  [֛[[֛9   &%2".4> 6=!26=4&#!54&֛[[֛[[%  [֛[[֛ &   %2".4>&";;265326֛[[֛[[K &   [֛[[֛@  %2".4>#"#"276&+4&֛[[֛[[  & [֛[[֛  2".4>%&277>7.'.'"'&65.'6.'&767>'&>7>7&72267.'4>&'?6.'.'>72>՛\\՛\\d+: =?1 " "/ ?9 #hu!$ 0 E.(,3)  (     *!A 7 ,8 !?*  \՛\\՛  ' "r"v G  .&* r$>   #1    %  *  '"  $  g2( % 67'"/&47&6PM<;+oX"O\e~Y+" n+We`#'7;!2#!"&=46#3!2#!"&=46!!!2#!"&=46!!d);;));;);;));; );;));;,;)d);;)d);dd;)d);;)d);dd;)d);;)d);dddL !2#!"&46!|;**Dd%32!2!5#!463!54635#!"&=);,); ;),;);));;)d;)pdd);d);dddD);;)+AW!2"/&546)2/"/&4?'&6#!"&54676276#!"&?'&4?622,^j^5,^j^/j^^^^j^j^,^j^&j^,^^^j#;CK2".4>"2>4&$2"&4$2#"'"&546?&542"&4$2"&4ݟ__ݠ^^oooo-- - L- 73H3)z - - - - _ݠ^^ݟWooo -!!- -! $33$ 1~ - - - -Z[%676&'&#"3276'.#"&477>32#"&'&6767632'."[v_"A0?! -  Y7J3$$ )G"#A.,= # (wnkV8@Fv"0DG([kPHNg8B*[eb2!5(7>B3$$' )M"#!7)/c# *xnfL@9NDH7!$W]B$&dXDD>.54>"".#"2>767>54&0{xuX6Cy>>xC8Zvxy#!?2-*!')-?"CoA23:+1! "3)@ +)?jDH-Sv@9yUUy9@vS-H-&65&&56&oM8J41<*.0(@  )*D*2Om9w.2&/7'/&477"/&4?BB8"._{iBBi BBBBBB7._BB^*k"5._{jBBFi BBBBBB77/_2#!"&54>!"264d:;));XV==V=.2G);;)3-D=V==V "/''!'&462*$3, #**#4$*' 2@K#.'#5&'.'3'.54>75>4.&ER<, 3'@" MOW(kVMbO/9X6FpH*M6&+  4C4%dfJ2#4.#"3#>36327#".'>7>'#53&'.>761T^'<;%T)-6"b "S5268 jt&'V7  0 $ݦ -$aPN(?",9J0* d2>2 ""   7Gd/9+DAL!X32"/&6;3+##"&?62*Ȗ*,|%#5##!32"/&6;3353!57#5!ddd,*dc,dd|ddd!%32"/&6;33!57#5!#5##!35*X,ddd,d,ddPdddL32"/&6;3##53#5#!35*Xdddd,d, dPddL32"/&6;3#5#!35##53*d,ddd, ddd32"/&6;3#53!5!!5!!5!*d,dpd , 32"/&6;3!5!!5!!5!#53* dpd,d, LL!2#!"&546!"3!2654&^pg );;));;Lp;) );;));LL+!2#!"&546!"3!2654&&546^pd );;));;oLp;) );;)); $  LL+!2#!"&546!"3!2654&!2"/&6^pg );;));; $ Lp;) );;));LL+!2#!"&546!"3!2654&#!"&?62^pg );;));; p $Lp;) );;));L5!2#!"&=463!2654&#!"&=46&=#"&=46;546&p);;)>DLpd;));d&  #%2"+'&7>?!"'&766763 ,  P'' K    S#  nnV/L5!2#!"3!2#!"&546&=#"&=46;546^>);;)pDLd;) );d&  1!2/"/&47'&6#"3!26=7#!"&5463!m)8m);;));Ȼp,pm)8m;) );;)֥#2".4>"2>4&2"&4ٝ]]ٝ]]qqqq{rrr]ٝ]]ٝGqqqsrrrL#3232"'&6;46!2!54635 ' gdV^|d22L# ++"&=#"&7>!2!54635Gz " 'gdM !d22LK" 62"'&4?62!2!54635qgdq#d22L #'762'&476#"&?'7!2!54635*MMК=gdML*Л:d22L#'/'7'&6"/&4?!2!54635^WЛԛL*MgdКԚPM*MXd22% ! q3gqdL+!#"&546;!3#53LDdddp,E/'&"!#"&546;!3#53"/&4?6262L_  Ȗdddj\jO)_ p,j[jO) >'.!#"&546;!3#53"/"/&4?'&4?62762Lg%dddFF))FF))gp,F))FF))F/!"!#"&546;!3#533232"/&6;546L dddd*p,/'&"!#"&546;!3#53++"&=#"&?62L*ndddd*pp,L !2!546#!"&5!52LPdL&}-1;&=!5!546#"&=46;#5376!!/&4#5;2+p/22ddpddd33*ȖdȖ*yddQ%6+"&5.546%2+"&5.54>323<>3234>^%"% "  d d 1t5gD >?1) A..@  ^  ^ dL3"!5265!3!52>54&/5!"!4"2pK Kp"2KKL8 88 %v% 88 x88 %v% 8LL  $(4!2#5'!7!!2#!"&546!55%!5#!!'!73wipdw%,);;));;),p,ddibbd;) );;));dfdd&767>".'.7.wfw3 .1LOefx;JwF2 1vev/ 5Cc;J|sU@L#A2/.=& &=>2#!"&=46754>ud?,  1;ftpR&mm&L!((" """" '$+  222/2 ! '!'3353353!2+!7#"&46!2!546L J LP*dd*22dL #"!4&#"!4&!46;2d);,;gd);,;;)d);L;));;)D););;)L%)!2#!"&546!#3!535#!#33||D| ,dddL| |||Dddd,ddd,L%)!2#!"&546!#5##3353#33||D| dddddddddL| |||Dddd,L#!2#!"&546!#3!!#3!!||D| ,,L| |||DdddL!2#!"&546!- ||D| ,L| |||D ,L )!2#!"&546!!!#";32654&#||D|dDd&96) )69&L| |||DdVAAT,TAAVL%)!2#!"&546!#3!535#!##53#53||D| ,ddddL| |||Dddd, d dL#'!2#!"&546!3!3##5335#53||D|DdXddd,ddL| |||Dp ddL"&!2#!"&546!#575#5!##53#53||D| d,ddddL| |||Dp2Ȗd d d %2".4>"2>4&!!!'57!۞^^۞^^qqqql,dd,^۞^^۞Lqqqddd '+2".4>"2>4&#'##!35۞^^۞^^qqqql2dddd,^۞^^۞Lqqqd2d2dddddA 62632+54&#!"#"&5467&54>3232"/&6;46n,,.xxPpVAbz  & AwasOEkdb  A32632&"#"&5467&54>++"&5#"&76762n,+.yxZ % OqVAb   AwaxchsOEkdc  dLm%5!33 33!#"!54&#Ԫ2dd,,Md22y7/2#"'2!54635#"&547.546324&546X^Y{;2 iJ7--7Ji/9iJqYZ=gJi22iJX5Jit'*BJb{"&'&7>2"3276767>/&'&"327>7>/&'&&"267"327>76&/&"327>76&/&oOOoSSoOOoS=y" $GF`   Pu "Q9   ccccVQ:   Pu "GF`   y" $ooSWWSo++oSWW"y  `FG # uP  :Q # cccc:Q # uP  $`FG # "y  d "!#5!!463!#53'353!"&5+, ?,dԢdu       d !! 463!#5##5#7!"&=)+5, ?,>dԪ |  ^G |d 77 P#3!#732!!34>3!!ddԢ!,d!s, d,+$d$+ppLL293232#!"&=46;54652#!"'74633!265#535d22s);;);)X>,>XL2dd2;));FD);>XXԢddL6=3232#!"&=46;54652#3#!"&54633!265#535d22s);!);;)X>,>XL2dd2;) $+;) );>XXԢd  #!"&762#";2676&35} ,, }@D:#6#:&77&P'L. dd LL/?O_o32+"&=4632+"&=46!32+"&=4632+"&=46!32+"&=46!32+"&=4632+"&=46!32+"&=46!32+"&=46                  L                  )33#!2!&/&63!5#5353!2+!7#"&46!2!546dd^>1B)(()B1>^dd> J LPdO7S33S7Odd|*dd*22+52#4!!2!'&63!&54!2+!%5#"&46!2!5460P9<:H)"Z" )HJLP;))%&!!&**22$.2"&432!65463!2+!7#"&46!2!546 jjj."+''+# J LPjjj9:LkkL:9r*dd*22,62"&5477'632!65463!2+!7#"&46!2!546X/[3oo"o"."+''+# J LPk6NooN>Qo 9:LkkL:9r*dd*22",!!.54>7!2+!7#"&46!2!546X,%??M<=BmJ J LP9fQ?HSTTvK~*dd*22)2!546754!2#3#3#3#!"&546/R;.6p6.d6\uSpSuu;)N\6226\N)G6.dddddSuuSSudLL/3!2#!"&546!2#!"/!"&4?!"&=46!'|  % XW & dDdL D 2  % XX %  2 dddL#-7!2#4&+"#4&+"#546!2!46+"&=!+"&= Sud;));d;));du);P;ddLuS);;));;)Su ;),); 2222  !&4762 !2!546 'YV/ |UYY(n0U22!/.#!"3!26=326!546;546;33232!'p'q*}20/222,2 "!#!5463!#5!#!"&5463!#5,  w,, v  w, O,T    dGFV32676'&7>++"&?+"'+"&?&/.=46;67'&6;6#";26=4&KjI C   )V=>8'"d 1*) "dT,| -otE  GAkI ! "% ,=?W7|&F@Je5&2WO_e_ 2  2 ~ $4<Rb%6%32!2&'&#!"&=46#";2654&'&"2647>?&/&6%?6'.'.. +jCHf7" *:>XXP* @--@- -?0 !3P/|)( )f!% =  &* x"62&CX>>X83 D-@--@ۂ # =I+E( //}X&+ 5!H d9Q`o322#+"&=#+"&=#"&=46;#"&=46;546;23546!2>574.#!2>574.#q Oh ..40:*"6-@# d   KK   d)  )k)  ) m!mJ.M-(2N-;]<* K  KK  K X K  KK  "p "),!2#!"&'.546"!7.# Vz$RR(z }VG+0 )IU!zV`3BBWwvXZ3Vz&--% ,(1#32#!"&546+"&=ۖgT)>)TH66g )TT)g6633#!"&546+"&=`T)>)TH66B)TT)g66 %'5754&>?' %5%Ndd/\^^<ǔȖ  (Abd 2"&4$2"&4$2"&4|XX|X|XX|X|XX|X X|XX|XX|XX|XX|XX|L2"&42"&42"&4|XX|XX|XX|XX|XX|XLX|XX|X|XX|X|XX|ddLL/!2#!"&=46!2#!"&=46!2#!"&=46}  J    J    J L  p  p  /3!2#!"&546!"3!2654&!2#!"&546!5^ );;)X);; G ;));;)X);d,dddL;!2+32+32+32#!"&46;5#"&46;5#"&46;5#"&46222222222222L********, *.62"&%#462"&%#46"&=32W??WW??||||||*(CBB||||԰||||ӐB76+2+"47&"+".543#"&'&676/!'.6E*  '?) T 0I' *L #3{,# n  6F82 *5#"#!#4.+3#525#"#5!2 &2p"& 2D d 2d  dd R , W 22 L 05"'./#!5"&?!##!"&=463!2E  1;E%= !'y,2 " # 22+."A2VddGJ!2#!"&546#"3!26=4&#"'&?!#"3!26=4&'"'&'#&#2LFF &  7 ? 9   9 gLR   2 2  2 2 $ #'!5!!2#!"&546)2#!"&546!PpmpG,Ld|pd,#'!2#!"&546!2#!"&546!!5!2pmpG,P| pd,dd'+!235463!23##!"&=##!"&546!2dddpdp,d ,'3#3!2#!"&546!!2#!"&546dddpG,|dpd, pdL'+32+!2#!"&5463!5#"&546;53!X|^d,Lpdpdd,'!#3!2#!"&546!!2#!"&546ddvpG,|dpd, p,0o #"&54632a5*A2~ 6'&4O**{))*2A~ !2"'&6d)***2,~o #!"&762{))*a**( 5-5!5!Lc d 1#3!35#5!34>;!5".5323!,P2 &d2"d& 2dd,dd  dd & ,L%1#4.+!52>5#"#!#3!35#5! 2 &d2p"d& 2 ,, dd & ,dd,ddfrJ32 +"'&476 0  ) J 00   >fJ32+"&7 &6S )  0 J ))   fJr"'&=46 4 ))  w  )  0f>J ' &=4762j  00  )  0  =:#463267>"&#""'./.>'&6|Vd&O "(P3G*+*3M, :I G79_7&%*>7F1 ||5KmCKG\JBktl$#?hI7 !2+&5#"&546!5X,p dddL!2%!#4675'=DXDd dQ,[u}4]ddMo__<vsvsQQ(dpEHEd{ d&ndd ddddd5d!u ,d;I]ddQEJadd9'dddd dy'dddddddd,d,A22>ff****NNNNNNNNNNNNNN"~Fn2b\r bb 6 ( L 0  X * ^ h(T*v 8|t*<6`R.j(h6h^2Dl.vb F !2!v!"@""##"#8#z##$$0$^$$%4%`%&&~&'P''(4(p())*&*J*+ +z,,h,,---.(.f..//F/~//0>0011`112$2^223"3>3h344`445,556>6|677N7788B889 9J99::l::;;<:>>?(?n??@H@@AA~BBBCCBCvCCDD`DDEZEFFtFFG6GvGGHH2HNHjHHII8I^IIJJ.JR@. j (|  L 8 x6 6   $ $4 $X | 0 www.glyphicons.comCopyright 2014 by Jan Kovarik. All rights reserved.GLYPHICONS HalflingsRegular1.009;UKWN;GLYPHICONSHalflings-RegularGLYPHICONS Halflings RegularVersion 1.009;PS 001.009;hotconv 1.0.70;makeotf.lib2.5.58329GLYPHICONSHalflings-RegularJan KovarikJan Kovarikwww.glyphicons.comwww.glyphicons.comwww.glyphicons.comWebfont 1.0Wed Oct 29 06:36:07 2014Font Squirrel2       !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     glyph1glyph2uni00A0uni2000uni2001uni2002uni2003uni2004uni2005uni2006uni2007uni2008uni2009uni200Auni202Funi205FEurouni20BDuni231Buni25FCuni2601uni26FAuni2709uni270FuniE001uniE002uniE003uniE005uniE006uniE007uniE008uniE009uniE010uniE011uniE012uniE013uniE014uniE015uniE016uniE017uniE018uniE019uniE020uniE021uniE022uniE023uniE024uniE025uniE026uniE027uniE028uniE029uniE030uniE031uniE032uniE033uniE034uniE035uniE036uniE037uniE038uniE039uniE040uniE041uniE042uniE043uniE044uniE045uniE046uniE047uniE048uniE049uniE050uniE051uniE052uniE053uniE054uniE055uniE056uniE057uniE058uniE059uniE060uniE062uniE063uniE064uniE065uniE066uniE067uniE068uniE069uniE070uniE071uniE072uniE073uniE074uniE075uniE076uniE077uniE078uniE079uniE080uniE081uniE082uniE083uniE084uniE085uniE086uniE087uniE088uniE089uniE090uniE091uniE092uniE093uniE094uniE095uniE096uniE097uniE101uniE102uniE103uniE104uniE105uniE106uniE107uniE108uniE109uniE110uniE111uniE112uniE113uniE114uniE115uniE116uniE117uniE118uniE119uniE120uniE121uniE122uniE123uniE124uniE125uniE126uniE127uniE128uniE129uniE130uniE131uniE132uniE133uniE134uniE135uniE136uniE137uniE138uniE139uniE140uniE141uniE142uniE143uniE144uniE145uniE146uniE148uniE149uniE150uniE151uniE152uniE153uniE154uniE155uniE156uniE157uniE158uniE159uniE160uniE161uniE162uniE163uniE164uniE165uniE166uniE167uniE168uniE169uniE170uniE171uniE172uniE173uniE174uniE175uniE176uniE177uniE178uniE179uniE180uniE181uniE182uniE183uniE184uniE185uniE186uniE187uniE188uniE189uniE190uniE191uniE192uniE193uniE194uniE195uniE197uniE198uniE199uniE200uniE201uniE202uniE203uniE204uniE205uniE206uniE209uniE210uniE211uniE212uniE213uniE214uniE215uniE216uniE218uniE219uniE221uniE223uniE224uniE225uniE226uniE227uniE230uniE231uniE232uniE233uniE234uniE235uniE236uniE237uniE238uniE239uniE240uniE241uniE242uniE243uniE244uniE245uniE246uniE247uniE248uniE249uniE250uniE251uniE252uniE253uniE254uniE255uniE256uniE257uniE258uniE259uniE260uniF8FFu1F511u1F6AATPSABnzbd-2.3.2/interfaces/Config/templates/staticcfg/bootstrap/js/bootstrap.min.js0000644000000000000000000011026513217005257026221 0ustar 00000000000000/*! * Bootstrap v3.3.7 (http://getbootstrap.com) * Copyright 2011-2016 Twitter, Inc. * Licensed under the MIT license */ if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'

'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/css/chartist.min.css0000644000000000000000000002636413217005257024346 0ustar 00000000000000.ct-double-octave:after,.ct-major-eleventh:after,.ct-major-second:after,.ct-major-seventh:after,.ct-major-sixth:after,.ct-major-tenth:after,.ct-major-third:after,.ct-major-twelfth:after,.ct-minor-second:after,.ct-minor-seventh:after,.ct-minor-sixth:after,.ct-minor-third:after,.ct-octave:after,.ct-perfect-fifth:after,.ct-perfect-fourth:after,.ct-square:after{content:"";clear:both}.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-grid-background,.ct-line{fill:none}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart-donut .ct-label,.ct-chart-pie .ct-label{dominant-baseline:central}.ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:end}.ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{stroke-width:4px}.ct-area{stroke:none;fill-opacity:.1}.ct-bar{fill:none;stroke-width:10px}.ct-slice-donut{fill:none;stroke-width:60px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#d70206}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#d70206}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#f05b4f}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#f05b4f}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#f4c63d}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#f4c63d}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#d17905}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#d17905}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#453d3f}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#453d3f}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#59922b}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#59922b}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#0544d3}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#0544d3}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#6b0392}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#6b0392}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#f05b4f}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#f05b4f}.ct-series-j .ct-bar,.ct-series-j .ct-line,.ct-series-j .ct-point,.ct-series-j .ct-slice-donut{stroke:#dda458}.ct-series-j .ct-area,.ct-series-j .ct-slice-donut-solid,.ct-series-j .ct-slice-pie{fill:#dda458}.ct-series-k .ct-bar,.ct-series-k .ct-line,.ct-series-k .ct-point,.ct-series-k .ct-slice-donut{stroke:#eacf7d}.ct-series-k .ct-area,.ct-series-k .ct-slice-donut-solid,.ct-series-k .ct-slice-pie{fill:#eacf7d}.ct-series-l .ct-bar,.ct-series-l .ct-line,.ct-series-l .ct-point,.ct-series-l .ct-slice-donut{stroke:#86797d}.ct-series-l .ct-area,.ct-series-l .ct-slice-donut-solid,.ct-series-l .ct-slice-pie{fill:#86797d}.ct-series-m .ct-bar,.ct-series-m .ct-line,.ct-series-m .ct-point,.ct-series-m .ct-slice-donut{stroke:#b2c326}.ct-series-m .ct-area,.ct-series-m .ct-slice-donut-solid,.ct-series-m .ct-slice-pie{fill:#b2c326}.ct-series-n .ct-bar,.ct-series-n .ct-line,.ct-series-n .ct-point,.ct-series-n .ct-slice-donut{stroke:#6188e2}.ct-series-n .ct-area,.ct-series-n .ct-slice-donut-solid,.ct-series-n .ct-slice-pie{fill:#6188e2}.ct-series-o .ct-bar,.ct-series-o .ct-line,.ct-series-o .ct-point,.ct-series-o .ct-slice-donut{stroke:#a748ca}.ct-series-o .ct-area,.ct-series-o .ct-slice-donut-solid,.ct-series-o .ct-slice-pie{fill:#a748ca}.ct-square{display:block;position:relative;width:100%}.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-square:after{display:table}.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-minor-second{display:block;position:relative;width:100%}.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-minor-second:after{display:table}.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-major-second{display:block;position:relative;width:100%}.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-major-second:after{display:table}.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-minor-third{display:block;position:relative;width:100%}.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-minor-third:after{display:table}.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-major-third{display:block;position:relative;width:100%}.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-major-third:after{display:table}.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-perfect-fourth:after{display:table}.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-perfect-fifth:after{display:table}.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-sixth{display:block;position:relative;width:100%}.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-minor-sixth:after{display:table}.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-golden-section{display:block;position:relative;width:100%}.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-golden-section:after{content:"";display:table;clear:both}.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-major-sixth{display:block;position:relative;width:100%}.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-major-sixth:after{display:table}.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-seventh{display:block;position:relative;width:100%}.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-minor-seventh:after{display:table}.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-seventh{display:block;position:relative;width:100%}.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-major-seventh:after{display:table}.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-octave{display:block;position:relative;width:100%}.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-octave:after{display:table}.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-major-tenth{display:block;position:relative;width:100%}.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-major-tenth:after{display:table}.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-major-eleventh{display:block;position:relative;width:100%}.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-major-eleventh:after{display:table}.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-twelfth{display:block;position:relative;width:100%}.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-major-twelfth:after{display:table}.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-double-octave{display:block;position:relative;width:100%}.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-double-octave:after{display:table}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0}SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/css/login.css0000644000000000000000000000201513217005257023036 0ustar 00000000000000body { overflow-y: scroll; background-color: #E4E4E4; } * { border-radius: 0 !important; } .btn, .btn:hover, .btn:active, .btn:focus { box-shadow: 1px 1px 1px rgba(0,0,0,.1) !important; background-color: white !important; } .logo-header { padding-bottom: 10px; } .logo-header svg { height: 55px; width: 198px; } .account-wall { width: 300px; position: absolute; top: 30%; left: 50%; transform: translate(-50%, -30%); } .text-center a { position: absolute; right: 13px; top: 12px; color: #636363; font-size: 1.2em } .text-center a:hover { color: black !important; } .form-signin .alert { margin: 5px 0px; } .form-signin input { margin-top: 5px } .form-signin .btn { width: 100%; margin-top: 10px; font-weight: bold; } .btn .glyphicon { margin-left: 3px; float: right; top: 1px; font-size: 1.2em; } input[type="checkbox"] { width: 16px; height: 16px; margin-top: 2px; } label { color: #636363; }SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/css/style.css0000644000000000000000000006033213217005257023074 0ustar 00000000000000body { overflow-y: scroll; background-color: #E4E4E4; } #logo { display: block; margin: auto; margin-top: 3px; } #content { color: #000; padding: 15px 20px 20px; font-size: 13px; padding-top: 65px; padding-bottom: 20px; } .colmask { z-index: 20; position: relative; clear: both; float: left; overflow: visible; border: 1px solid #dfdede; background-color: #FFF; width: 100% } .advanced-button { float: right; width: auto; margin: 0 4px 0px 0px; font-size: 13px; color: inherit; height: auto; padding-bottom: 5px; } #advanced-settings-button { float: left; margin: 2px 7px 0px 0px; } .advanced-buttonSeperator { width: 1px; height: 34px; background-color: #dfdede; float: right; margin: 0px 10px; } .section, #addFeed, #addFeedContent { border-bottom: 1px solid #dfdede; overflow: auto; } .col2 { z-index: 10; float: left; overflow: auto; padding: 12px; width: 250px; } .col1 { z-index: 11; width: 100%; float: none; padding: 12px 0 0; } .col2 h3 { background: none repeat scroll 0 0 #666; color: #fff; padding: 6px 8px; vertical-align: middle; margin: 0; font-size: 1.4em; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; position: relative; } .col2 h3 a { display: none; position: absolute; right: 8px; bottom: 0.4em; color: white; font-size: 0.8em; } .section:hover .col2 h3 { padding-right: 25px; } .section:hover .col2 h3 a { display: inline-block; } .main-helplink { display: block; position: static; float: right; color: black !important; padding: 0px; font-size: 1.2em; } .example { background-color: #fefeee; } .presets { margin-bottom: -6px; } .presets input { margin: 2px 0; } .presets input[type="button"] { margin: 0px 2px 6px 0px; } label.config, .field-pair h5 { overflow: auto; float: left; width: 24%; font-weight: 700; display: block; text-align: left; margin-right: 10px; margin-left: 20px; padding-top: 5px; } label.config-hover { cursor: pointer; } label.narrow { width: 200px!important; } label.wide, .field-pair h5 { width: auto!important; } .field-pair h5 { margin-bottom: 5px; line-height: normal; } .desc { display: block; margin: 0 0 0 24%; padding: 3px 0 0 31px; font-size: 12px; font-style: italic; } .desc.narrow { margin: 0 0 0 200px!important; } input[type="checkbox"]+.desc { padding-top: 6px; } .desc-check { font-size: 12px; font-style: italic; padding: 0 1px; } .col2 p, .col2-cats { font-size: 12px; color: #666; margin: 1em 0; } .field-pair { padding: 6px; clear: both; float: none; overflow: hidden; min-width: 555px; } .Key tr:nth-child(odd), .tab-pane tr:nth-child(odd), .even { background-color: #F8F8F8; } .field-pair:last-child, .no-field-pair-bg { background-color: transparent; } .alt, .infoTableSeperator.alt { background-color: #F8F8F8; } .success { color: #5cb85c !important; } .typeahead.dropdown-menu { padding: 0; min-width: 300px; margin: 0; } .typeahead.dropdown-menu>li>a { padding-left: 12px; font-size: 13px; } .typeahead.dropdown-menu>.active>a, .typeahead.dropdown-menu>.active>a:focus, .typeahead.dropdown-menu>.active>a:hover { color: black; background-color: #E5E5E5; } #content fieldset { border: 0; outline: 0; min-width: 350px; margin: 0; padding: 0 12px 12px 6px; } textarea, select, input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"] { padding-left: 5px; border: 1px solid #d4d0c8; } select option { padding-left: 5px; } #check_new_rel option, #check_new_rel { text-transform: capitalize; } input[type='checkbox'] { display: block; white-space: nowrap; padding: 0; margin-left: 5px; } textarea:hover, input[type="date"]:hover, input[type="datetime"]:hover, input[type="datetime-local"]:hover, input[type="email"]:hover, input[type="month"]:hover, input[type="number"]:hover, input[type="password"]:hover, input[type="search"]:hover, input[type="tel"]:hover, input[type="text"]:hover, input[type="time"]:hover, input[type="url"]:hover, input[type="week"]:hover, textarea:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="email"]:focus, input[type="month"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="time"]:focus, input[type="url"]:focus, input[type="week"]:focus { background-color: #fffff0; border: 1px solid #aaa; } .col1 input[type='checkbox'] { position: absolute; top: auto!important; height: 16px; width: 16px; margin-left: 0; } .col2 input[type='checkbox'] { height: 16px; width: 16px; margin-top: 0; } .readonly { background-color: #eff; } .multiple_cats { padding: 5px 10px!important; margin-top: 2px; } .padding { padding: 6px; } .disabled, .disabled input, .disabled .clearBtn, .disabled .patternKey, .disabled .show_qrcode, .disabled .generate_key, .disabled .generate_cert { color: #aaa !important; } .padTable p { margin-top: 0; } .nomargin { margin: 0; } .copyright { margin: 0; padding: 6px; } .path { color: #000; font-weight: 400; } .darkred { color: #d9534f; } .scheduleEntry { padding: 8px 0; } .time { padding: 0 10px; color: #000; font-weight: 700; } .frequency { padding-right: 5px; letter-spacing: .5px; } .padTable { padding: 15px; overflow: auto; clear: both; } .label { font-style: normal; } .padTable h3 { margin-top: 0; } tr.separator { height: 30px; } .catTable th, .catTable td { padding: 5px; } .catTable th { text-align: center; } .catTable .glyphicon-option-vertical { color: #808080; display: block; margin-right: -5px; cursor: move; } .Categories form:not(.sorting-row) .glyphicon-option-vertical { visibility: hidden; } .Categories form.sorting-row:nth-child(2n-1) tr { background-color: #F8F8F8; } .Categories form:first-of-type tr:last-of-type { background-color: #FFFFE0; } .Categories hr { margin: 5px; } .RSS .rss-section input[type="text"] { max-width: 180px; } .RSS .catTable select { max-width: 120px; } .RSS input[type="checkbox"] { width:16px; height: 16px; margin-top: 0px; } .RSS form[action="add_rss_feed"] tr:nth-child(even) { border: 1px solid #E5E5E5; } .RSS .tab-pane table th:not(.no-sort) { cursor: pointer; } .RSS .tab-pane table th:not(.sorted) { padding-right: 12px; } .RSS .tab-pane table th.sorted { padding-right: 0px; } .RSS .tab-pane table th.sorted.ascending:after { content:''; display: inline-block; width: 0; height: 0; margin-left: 4px; vertical-align: middle; border-bottom: 4px dashed; border-right: 4px solid transparent; border-left: 4px solid transparent; } .RSS .tab-pane table th.sorted.descending:after { content:''; display: inline-block; width: 0; height: 0; margin-left: 4px; vertical-align: middle; border-top: 4px dashed; border-right: 4px solid transparent; border-left: 4px solid transparent; } .Config .table { margin: 0; border: 1px solid #ddd } .Config .colmask { margin-bottom: 12px; } .Config .padding { padding: 13px; } .Config th { width: 20%; min-width: 150px; padding-left: 15px !important; } .Config .label { font-size: 90%; } .Config td .glyphicon-question-sign { color: black !important; top: 3px; } .tab-pane thead tr { background-color: transparent !important; } .default { background-color: #ffffe0; border-bottom: 1px solid #aaa; border-top: 1px solid #ddd; } .hidden { visibility: hidden; display: block!important; } .float-left { float: left; } .float-right { float: right; } .align-left { text-align: left; } .align-right { text-align: right; } .align-center { text-align: center; } .nowrap { white-space: nowrap; } .Key { display: none; border: 1px solid #ccc; width: 425px; } .Key th { background: none repeat scroll 0 0 #666; color: #fff; margin: 0; padding: 3px 9px; } .Key td { padding: 2px; } .Key tr { border-bottom: 1px solid #ccc; } #infoTable { font-size: 12px; width: 100%} #infoTable tr { line-height: 17px; } .infoTableHeader, .infoTableCell { padding: 6px; word-break: break-all; } .infoTableHeader { font-weight: 700; width: 160px; } .infoTableSeperator { border-top: 1px solid #ddd; } .icon { padding-left: 5px; } .modal-content { box-shadow: none; } .modal-backdrop { background-color: white; } .modal-backdrop.in { opacity: 0.8; } .modal-body { padding-bottom: 0; } .modal-dialog { padding: 3px; } .modal-body h4 { word-break: break-all; } .modal-header { background-color: #3C3C3C; color: white; border: 0; padding:11px 12px 8px; } .modal-header .close { opacity: 0.5; background: transparent; color: white; text-shadow: none !important; font-weight: normal !important; font-size: 32px; vertical-align: middle; margin-top: -5px; font-family: arial, sans-serif !important; } .modal-header .close:hover { opacity: 1; } .modal-dialog { transform: scale(0.7) !important; -webkit-transform: scale(0.7) !important; opacity: 0 !important; transition: all 0.3s !important; } #modal_qr .modal-body canvas { padding: 10px; margin-bottom: 10px; } .modal.in .modal-dialog { transform: scale(1) !important; -webkit-transform: scale(1) !important; opacity: 1 !important; } .btn-default.fileBrowser, .btn-default.clearBtn { margin-left: -1px !important; box-shadow: 1px 0px 1px rgba(0,0,0,.1) !important; } #filebrowser_modal .list-group-item { font-weight: bold; } #filebrowser_modal .list-group-item span { margin-right: 10px; top: 0; } #filebrowser_modal .checkbox { float: left; margin: 8px 5px 0x; } #filebrowser_modal .checkbox input { margin-top: 1px; } #filebrowser_modal .checkbox input+span { opacity: 0.6; font-weight: bold; } #filebrowser_modal .checkbox input:checked+span, #filebrowser_modal .checkbox span:hover { opacity: 1; } /* Fix for shifting scrollbars when opening modals */ .modal-open[style="padding-right: 17px;"] .navbar-fixed-top { padding-right: 17px; } .modal-open[style="padding-right: 15px;"] .navbar-fixed-top { padding-right: 15px; } .modal-open[style="padding-right: 13px;"] .navbar-fixed-top { padding-right: 13px; } /* -- */ h2.activeRSS { margin-bottom: 10px; } .activeRSS a, .activeRSS a:visited { text-decoration: none; color: #000; } .activeRSS a:hover { color: #4b4742; } .activeRSS a:first-of-type { text-decoration: underline!important; } .favicon { background-position: center center!important; background-size: 16px 16px; opacity: 1; top: -1px; height: 16px; width: 16px; float: left; margin: 0 6px 0 2px; text-align: center; } .source-icon span { top: -3px; } .feed { text-decoration: none; } .feed_enabled { color: #000; } .feed_disabled { color: red !important; } #subscriptions { border: 1px solid #E5E5E5; } .data-row { border-top: 1px solid #E5E5E5; } #subscriptions td { border: 0 none; padding-top: .4em; } #subscriptions .chk { padding: 5px; padding-top: 8px; vertical-align: middle; } #subscriptions .title { font-weight: bold; padding-right: .3em; width: auto; } #subscriptions .favicon { margin-left: 8px; } .ie6 .subscription-title { width: 20em; } .subscription-title, .subscription-title:hover { width: 20em; overflow: hidden; white-space: nowrap; display: block; text-decoration: underline; color: black; } .controls { text-align: right; padding-right: 5px; white-space: nowrap; } .feed-row td { color: #777; max-width: 515px; padding: 0 0 .5em; } .feed-row div { overflow:hidden; white-space: nowrap; text-overflow: ellipsis; } .tab-content .catTable { width: 100%; } .tab-content .catTable th { text-align: left; } .tab-content .catTable tbody { border: 1px solid #ddd; } .tab-content .catTable td { line-height: 2em; } .tab-content .catTable td:nth-child(4) { word-break: break-all; } .tab-content .catTable tr:hover td { background-color: #F2F2F2; } span.count { background-color: #6E6E6E; color: #fff; margin: -3px 0 0 5px; padding: 1px 10px; } a.current .count { background-color: #777!important; } a.current:hover .count { background-color: #333!important; } ul.tabs { margin: 0!important; padding: 0; height: 30px; } ul.tabs li { float: left; padding: 0; margin: 0; list-style-type: none; } ul.tabs a { float: left; font-size: 13px; display: block; padding: 5px 30px; text-decoration: none; border: 1px solid #dfdede; border-bottom: 0; color: black; margin-right: 2px; position: relative; top: 1px; outline: 0; } ul.tabs a:hover { background-color: #eee; color: #333; } ul.tabs li.active a { background-color: #eee; border-bottom: 1px solid #f8f4e7; color: #000; cursor: default; } .checkbox-days { float: left; } .checkbox-days p { margin: 0 0 5px 0; } .checkbox-days input { vertical-align: middle; margin-top: -1px; } .checkbox-days label { padding: 2px 20px; } .rating-filter { float: left; } .rating-filter p { margin: 0 0 10px 0; } .rating-filter select { vertical-align: middle; } .rating-filter input { vertical-align: middle; margin-top: -1px; } .rating-filter label { display: inline-block; padding-left: 0px; width: 100px; } .rating-filter input[type="checkbox"] { display: inline; } .rating-filter input[type="checkbox"] + label { padding-left: 20px; padding-top: 5px; width: auto; } .rating-filter p > span:first-child { float: left; width: 130px; } .rating-filter .desc { display: block; margin: 0px; padding-left: 103px; } /** EDITS 2015 **/ * { border-radius: 0 !important; } .collapsing { -webkit-transition: none; transition: none; } input[type=checkbox], input[type=radio] { margin-top: 2px; } input[type="button"], input[type="submit"] { color: #333; background-color: #fff; display:inline-block; padding:6px 12px; margin-bottom: 0; font-size:13px; font-weight:400; line-height:1.42857143; text-align:center; white-space:nowrap; vertical-align:middle; cursor:pointer; background-image:none; border:1px solid #ccc; height: 34px; } input[type="button"]:hover, input[type="submit"]:hover { color: #333; background-color: #e6e6e6; border-color: #adadad; } input[type="text"], input[type="email"], input[type="url"], input[type="number"], input[type="password"], textarea, select { line-height:1.42857143; padding:6px 12px; border: 1px solid #d4d0c8; box-shadow: inset 0 1px 1px rgba(0,0,0,.075); display:inline-block; vertical-align:middle; max-width: 100%; min-height: 34px; font-size: 13px; background-color: white; } input[type="text"]:not([size]), textarea { width: 300px; } input[type="number"], input[type="text"].smaller_input { width: 120px; } .btn { font-size: 13px; height: 34px; box-shadow: 1px 1px 1px rgba(0,0,0,.1) !important; } .btn .glyphicon { top: 2px; } .btn .glyphicon-ok, .btn .glyphicon-plus { top: 1px; } select { min-width: 200px; max-width: 300px; } input[disabled], select[disabled] { background-color: #eee; } select[multiple] { width:100%; padding: 0 !important; } .col1 select[multiple] { max-width: 300px; } select[multiple] option { padding:6px 12px; } input[type="checkbox"] { margin-top: 5px; } .Scheduling select, .Categories select, .RSS select { min-width: 120px; } .Categories select { max-width: 150px; } .Categories #content input { max-width: 150px !important; } .Scheduling form[action="addSchedule"] input[type="checkbox"] { margin-top: 0px; margin-left: -20px; } .Scheduling form[action="delSchedule"] input[type="checkbox"] { position: initial; float: left; margin: 9px 10px 0px 5px; } .navbar .container { padding-right: 0; } .navbar .nav>li>a { height: 50px; } .navbar-default { background-color: #FFF; border-bottom: 1px solid rgba(0, 0, 0, 0.2); margin-bottom: 10px; } .navbar-fixed-top { z-index: 1000; } .navbar-logo { display: inline-block; padding-right: 10px; padding-left: 10px; padding-top: 5px; margin-left: 5px; margin-bottom: -1px; } #search-menu .glyphicon { top: 3px; } #search-dropdown { right: 0; left: auto; width: 300px; padding: 5px; } #search-dropdown .dropdown-header { font-weight: bold; color: black; } #search-dropdown a { overflow: hidden; text-overflow: ellipsis; } .navbar-logo-small svg { height: 40px; width: 40px; } /* .navbar-logo-wide { display: none; } .navbar-logo-wide { padding-top: 9px; } .navbar-logo-wide svg { height: 36px; width: 130px; } */ .navbar-default .navbar-nav>li>a { color: black !important; } .navbar-default .navbar-nav>li>a:hover, .navbar-logo:hover { background-color: #e2e2e2 !important; } .navbar-default .navbar-nav>li>a.active { background-color: #ECECEC !important; } .navbar-default .navbar-nav>li>a>span, .navbar-default .navbar-nav>li>a>svg { display: none; } #navbar .glyphicon-folder-open { margin-right: 2px; } .rss-icon-svg { display: inline-block; margin-top: 1px; margin-bottom: -1px; width: 1em; height: 1em; } .rss-symbol { stroke: none; fill: white; } .col2 table { margin: 10px 0px; } .Servers .col2 .label { margin-top: 8px; font-size: 0.85em; float: right; line-height: 1.1em; } .Servers .col2.server-disabled .label { color: ##777 !important; } .Servers .col2 .label:nth-child(2) { opacity: 0.7; } .Servers .server-amounts-text { width: 20%; float: left; } .Servers .server-chart { float: right; width: calc(100% - 250px - 25%); text-align: center; position: relative; } .Servers .ct-series-a .ct-line { stroke: #666666; } .Servers .ct-series-a .ct-point { stroke: #666666; stroke-width: 4px; } .Servers .ct-series-a .ct-area { fill: #666666 } .Servers .ct-label { font-size: 1em; color: black; } .Servers .chart-selector-container { float: right; } .Servers .chart-selector-container .glyphicon { font-size: 1.3em; padding-right: 4px; top: 5px; } .Servers .ct-grid.ct-vertical:first-of-type { display: none; } .advanced-settings { display: none; } .Servers .port-highlight { animation: highlight-fade 1s ease-in 1; } .Servers .col2 label, .Email .col2 label { margin: 0; margin-left: 4px; margin-top: 2px; cursor: pointer; } .Servers .col2 button:first-of-type { margin-bottom: 8px; } .result-box .alert { margin-bottom: 0px; display: none; } .alert-translate { display: none; margin: 5px 0px 0px; } .server-disabled { background-color: #eee; } .Special .glyphicon-asterisk { margin-left: 8px; top: 3px; color: #666; } .host-warning { color: #F0AD4E; margin-left: 13px; top: 5px; font-size: 1.2em; } .fileBrowser .glyphicon { margin-right: 2px; top: 1px; } .main-restarting.in { text-align: center; opacity: 0.9; color: black; z-index: 2000; height: 100%; } .main-restarting.in div { position: relative; top: 30%; transform: translateY(-50%); } .main-restarting { display: block; background-color: white; } .main-restarting.in strong { font-size: 5em; display: block; } .main-restarting.in span { top: 10px; } .main-restarting small { font-size: 3rem !important; } .value-and-select input { margin-right: -5px; } .value-and-select select { min-width: 30px; } .dotOne, .dotTwo, .dotThree { opacity: 0; animation: dot 1.3s infinite; animation-delay: 0.0s; } .dotTwo { animation-delay: 0.2s; } .dotThree { animation-delay: 0.3s; } @keyframes dot { 0% { opacity: 0; } 50% { opacity: 0; } 100% { opacity: 1; } } @keyframes highlight-fade { 0% { background: #FEFEDA; } 100% { background: none; } } .spin-glyphicon { animation: spin 2s infinite linear; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(359deg); } } @media screen and (min-width: 1200px) { .Categories input[name="dir"] { max-width: 240px !important; } .navbar-nav { /* For extra wide languages like Polish */ margin-right: -150px; } } @media screen and (min-width: 768px) and (max-width: 1200px) { .navbar-default .navbar-nav>li>a>span, .navbar-default .navbar-nav>li>a:hover>strong, .navbar-default .navbar-nav>li>a.active>strong { display: inline; } .navbar-default .navbar-nav>li>a>svg { display: inline-block; } .navbar-default .navbar-nav>li>a>strong, .navbar-default .navbar-nav:hover>li>a.active>strong { display: none; } #search-menu>a>strong { display: none; } .RSS #content, .Categories #content { width: 100%; } } @media screen and (max-width: 1000px) { .col1 { float: right; padding: 5px 0px; } .col1 h5 { margin-left: 20px; } .col2 { width: 100%; padding: 10px; } .col2 p { margin-left: 20px; } .Servers .col2 button:first-of-type { margin-bottom: 0; } .Servers .server-chart, .Servers .chart-selector-container, .Servers .advanced-buttonSeperator { display: none; } .Servers .server-amounts-text { padding: 0px 15px 10px; width: inherit; } } @media screen and (max-width: 768px) { .navbar-default .navbar-brand-small { display: none; } .navbar .container { padding-right: 15px; } .navbar-default .navbar-brand-mobile { display: block; } .navbar-collapse.in .navbar-nav>li>a>span, .navbar-collapse.collapsing .navbar-nav>li>a>span { display: inline-block; width: 1.5em; } .navbar-collapse.in .navbar-nav>li>a>svg, .navbar-collapse.collapsing .navbar-nav>li>a>svg { display: inline-block; margin-right: 0.5em; } .navbar .nav>li>a { height: auto; } #search-menu { display: none; } .section .col2 h3 { padding-right: 25px; } .section .col2 h3 a { display: inline-block; } .main-restarting.in strong { font-size: 2em; font-weight: bold; } .main-restarting.in span { top: 2px; } .main-restarting.in small { font-size: 2rem !important; } #content { margin: 0 !important; padding: 0 !important; padding-top: 55px !important; } #content fieldset { min-width: 0; padding: 0 !important; } .colmask { border: none !important; } .col2 { padding: 10px; } .col2 h3 { margin: -10px -10px 0px; padding-left: 10px; } .col2 p { margin-left: 0px; margin-bottom: 0; } .col1 h5 { margin-left: 0px; } label.config { margin-left: 0px; margin-bottom: 2px; width: 100%; float: none; } .desc { margin: 0; margin-left: 3px; margin-top: 2px; padding: 0 !important; } .col1 input[type="checkbox"] { position: inherit; float: left; margin-right: 5px; margin-top: 0px; } div.field-pair{ min-width: 0; padding: 5px 10px; } .fileBrowserField { max-width: 65% !important; } ul.tabs a { padding-left: 5px; padding-right: 5px; } } SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/ico/android-192x192.png0000644000000000000000000000335513217004753024271 0ustar 00000000000000PNG  IHDRe52PLTEXA.#i(#@-Z  % ϑ߰#P? er 0"Yo p%`Ce?2 pOВ@@@ 0!exT Ͽ000pppSmctRNS?o0p@߿P _O`IDATxBQ?(V7yѷ`9o$L`A4h*TQ:h7@oV%Neff6rRR3)#IP+3eB t)iP0`}I4ܜ/ͧ19C flxN#ܡq3t" 0۠EoK `#оuG @ `\hDe lK;}à':!ءM lg(cl怃cN0()Gء3 i)p:whCRu9xj_+!lVx!8-luL0 /PjypUc h-pgdtJQ|z~`Do_V1`TYMίŅ qC&|a?Y,_ @y.dB) o( ']S^ī R```q7.u@yL}z pw_ > ͪi@ t4p@2J```mPR)vrQ|enB)Tu[ ?EƭeV~pWөIW'{NELο͘_NL+1?wA6i͙_v02W/A0 0?r &Dcھ-`eg% J;49-GpPW1db~)_gDg*'/ZY:MY[Oo\30IENDB`SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/ico/apple-touch-icon-120x120-precomposed.png0000644000000000000000000000236313217004753030312 0ustar 00000000000000PNG  IHDRxx2PLTE @-@0@3 @/ ??? 000```࿿@@@?,?-?2 ?-<*  pɔ  % #eP8 0"`CϑܤcJpYnS }({Ϥ tZdWBK4Y%Вeȏx3DtRNS_@ ϯp?o`0Pа)TIDATxiW@DRmBk[\ݗu$&{FO(aѝ5Hmx6p&\_2gO7Fzny˄OGF `nr f`i44 Xӷp4 o(uӷn6qi4=8 -Mۤ0u: Kca ^CĭD{DwKSa4 &ü[ 0i6lqL:07pKa-M눥 0a6 oq:;4u`־A[pKa[7qKbi,O;ȭ$Dq[9+Dq[`yzpwS *&q_B˦`%?TˎRvŗ-~o oEN3Ҕ=-xXW>֦8]fL_Jy=qk,]&-\-'ҕUtޖnJ?UW䌁޹ؿt9+QaWAt.'!yHJ&Cws)ﲮŵGX9(N(n\K`rgr)6 -G28~F)o"a83X^ Ρ_Dؙ 'Ojҿ\EqV\ `Ȣ^Uv){BbfPjn΃{<Qm(9> ˋ|)Bِ pIlu#f PPn-̩-kQҵ)?~c Uf[ҵ,W[sf]7kr/IENDB`SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/ico/apple-touch-icon-152x152-precomposed.png0000644000000000000000000000274313217004753030326 0ustar 00000000000000PNG  IHDR/5PLTE?,?2 @@@???ppp000@10$```4$?-?2 0!ojL  0" %#߰#`C@-P8Z hXAoXp ( } {^@3 pOϑYВ%pxtRNS@0`p PϐOWo_[C@IDATxysVKpeⲔBiۊ8ƁRHP(`3g3W~qթ~F<ɛe\*_ZR\Wu[u[A aGUVq``lyZ.%- 󕖄aҒ0*-ÆP\{lB%E`=%qƖ,_R_RfdalWX L~KO_o ķDa}%EavO 6RP &eOfda[ⰾ8Lvˡ"K*~YR&@qخ a]ՁJ0^R fZ0\R Kz# @*Ё[a=hIe %Ua=`Ie TuGJ0쁔÷a]`Iq÷K -`։ o}k ,xo`M 1-ra[~7 iJ0hGi鰖)и??[t˿_γ|'[/4ǖ"9Ȁ-ҬNsQӘ2pG43䧉d.ΰ4诩glST͌+W`jd#w@ƻb05̓g FWLU`K6e:ox(s=w%./ȭѱ=}K.ftaϒ{\*-/]тQ$DـWtȽKtmmd_4y(ڣ}K9, ]cavH;da;9,尔_QLla9kw;wH 4#rFae(l5YѸ_sm:6onMnrX;.Q\ǥ6ߘj]T3YŜFeNL3*W[&* 8SpkhʥQ?|ոwaՂ[AK]v>N\1ZK$P=#FR[KK"^29jU\GcDg%GnC$E'C&o\!s* Ld:=xTeKKeKSVU~;&{yWDmIENDB`SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/ico/apple-touch-icon-180x180-precomposed.png0000644000000000000000000000324713217004753030330 0ustar 00000000000000PNG  IHDR DPLTEВp `C?,```(@-P8n Z@@@000e %pYϤ p~ܤȏ]` {Y0"0& {ϑ# epppd%X=b`  ~\=-v"tRNS0`Р@ pPߟ_oOLĒvAIDATxw6a5̹9l%в b; l@w@T^~M||Gtf9ldsYhbnl]esZ}|^Ħ^qhC?83'YE>&ѮRhW}dVcGuXEwaM'uXFN갌a.M7}u4cx4뀠3p\#}hxGpu #T4F#>EG: hp1݁F.8z }d 4 cHAhd cꀣiNu1GCа>F9DꀣPꀣ':hD](с1}tktꀣPꀣ{uш> F#HhD1 #Aw0E7Ndߵscu#'`;hڧf3LmG;z+>b |]WiwuCۄT}em<hʤΦ*on/ԞoǻKWrA[2K}snR%E_^e|Mgt Nf jWpl6W'hl6Whlu/f>fۻ\ RвٖzC-jdO4вY~z} 8u,?me4Fw3@(ا~3-D^.8p.£j;6ێ1j5AQ/+\8Fwɣ=ڣ=ڣr߰m頷A?[@3hΣ=ڣ=ڣ#zG{G{Ô8˯h gߍ&ED,/ i8k6?~ң=ڣ=?K3yBޟh]O0Ӹ n).+*eYtw, O€8w-v6ߗXw=e̩xk(%Řژ3NS} fzhjcUp2}Y;[:fzG0c:fzNu,$qqE0*)ٿ3Z5 Wxu`:Y5.h[r-$F7$`MCBIENDB`SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/ico/apple-touch-icon-76x76-precomposed.png0000644000000000000000000000172613217004753030200 0ustar 00000000000000PNG  IHDRLLǗQ+IDATxdPr2]^m5XM h(C@΀6,0lcX9uVդjM@ .r{|8K/IOوcI$(q>,s;0XۭRZq`oҁ2kӜ ۙ-v ls<`= +N]VZu 0ZRak a = QA\C#0V$0"  ;`PܜZ",%R@uZ:TkŁmUK֫1QB0ʮ?]  TG|0ZR@j TG|0ZRsEVD^*$Fٛ/@)vQ 빬9. DXzؠܻ_ m3tΒoVs@{g2A7xbZӗQFRl-ձ;ԶF8v5V0uY=l ?Y$:,1EcGZIC `~ $E0~UK`,29FWkxhsmx˗23{_5-/:Xe`7`'b+=XZ-$'y: vxx_cqH !5`sM`ͱd`̀m[yN l׹r壉Kրa-,,&UI6"I߀0FFp ,_l0oW3safĀizg0hCPoz}ί fLF09Vs/9м"2f(ڧMS 7΍APh)KֳR|݆J?'hYUKɱ ZXjO2hXJze 3e`YۊwG+IENDB`SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/ico/favicon.ico0000644000000000000000000001246613217004753023332 0ustar 00000000000000 h&  (  @iiiii$$ii (( ii((ii$((#ia ((((iC_C_((((C_C_#(((("(((((((((((("((((((!((((((((((((((((?( @ ZZZZZZ ZZZ'&ZZ((ZZ((ZZ&((&ZZ(((( ZZ((((ZZ&((((%ZZ (((((( ZZ((((((ZP%(((((($JF (((((((( @<((((((((6%(((((((($ (((((((((( (((((((((($((((((((((# ((((((((((((((((((((((((#(((((((((((("(((((((((((((((((((((((((((("((((((((((((((!((((((((((((((((((((((((((((((((!(((((((((((((((( ((((((((((((((((('((((((((((((((((((??SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/ico/faviconpaused.ico0000644000000000000000000001246613217004753024534 0ustar 00000000000000 h&  (  @iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii?( @ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ??SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/ico/safari-pinned-tab.svg0000644000000000000000000000440113217004753025204 0ustar 00000000000000 SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/images/logo-arrow.svg0000644000000000000000000000112213217004753024500 0ustar 00000000000000SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/images/logo-full.svg0000644000000000000000000000421013217004753024311 0ustar 00000000000000SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/images/logo-small.svg0000644000000000000000000000243313217004753024464 0ustar 00000000000000SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/js/chartist.min.js0000644000000000000000000011642613217005257024015 0ustar 00000000000000/* Chartist.js 0.11.0 * Copyright © 2017 Gion Kunz * Free to use under either the WTFPL license or the MIT license. * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT */ !function(a,b){"function"==typeof define&&define.amd?define("Chartist",[],function(){return a.Chartist=b()}):"object"==typeof module&&module.exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.11.0"};return function(a,b,c){"use strict";c.namespaces={svg:"http://www.w3.org/2000/svg",xmlns:"http://www.w3.org/2000/xmlns/",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",ct:"http://gionkunz.github.com/chartist-js/ct"},c.noop=function(a){return a},c.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},c.extend=function(a){var b,d,e;for(a=a||{},b=1;b":">",'"':""","'":"'"},c.serialize=function(a){return null===a||void 0===a?a:("number"==typeof a?a=""+a:"object"==typeof a&&(a=JSON.stringify({data:a})),Object.keys(c.escapingMap).reduce(function(a,b){return c.replaceAll(a,b,c.escapingMap[b])},a))},c.deserialize=function(a){if("string"!=typeof a)return a;a=Object.keys(c.escapingMap).reduce(function(a,b){return c.replaceAll(a,c.escapingMap[b],b)},a);try{a=JSON.parse(a),a=void 0!==a.data?a.data:a}catch(b){}return a},c.createSvg=function(a,b,d,e){var f;return b=b||"100%",d=d||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS(c.namespaces.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),f=new c.Svg("svg").attr({width:b,height:d}).addClass(e),f._node.style.width=b,f._node.style.height=d,a.appendChild(f._node),f},c.normalizeData=function(a,b,d){var e,f={raw:a,normalized:{}};return f.normalized.series=c.getDataArray({series:a.series||[]},b,d),e=f.normalized.series.every(function(a){return a instanceof Array})?Math.max.apply(null,f.normalized.series.map(function(a){return a.length})):f.normalized.series.length,f.normalized.labels=(a.labels||[]).slice(),Array.prototype.push.apply(f.normalized.labels,c.times(Math.max(0,e-f.normalized.labels.length)).map(function(){return""})),b&&c.reverseData(f.normalized),f},c.safeHasProperty=function(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)},c.isDataHoleValue=function(a){return null===a||void 0===a||"number"==typeof a&&isNaN(a)},c.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;bf.high&&(f.high=c),h&&c0?f.low=0:(f.high=1,f.low=0)),f},c.isNumeric=function(a){return null!==a&&isFinite(a)},c.isFalseyButZero=function(a){return!a&&0!==a},c.getNumberOrUndefined=function(a){return c.isNumeric(a)?+a:void 0},c.isMultiValue=function(a){return"object"==typeof a&&("x"in a||"y"in a)},c.getMultiValue=function(a,b){return c.isMultiValue(a)?c.getNumberOrUndefined(a[b||"y"]):c.getNumberOrUndefined(a)},c.rho=function(a){function b(a,c){return a%c===0?c:b(c,a%c)}function c(a){return a*a+1}if(1===a)return a;var d,e=2,f=2;if(a%2===0)return 2;do e=c(e)%a,f=c(c(f))%a,d=b(Math.abs(e-f),a);while(1===d);return d},c.getBounds=function(a,b,d,e){function f(a,b){return a===(a+=b)&&(a*=1+(b>0?o:-o)),a}var g,h,i,j=0,k={high:b.high,low:b.low};k.valueRange=k.high-k.low,k.oom=c.orderOfMagnitude(k.valueRange),k.step=Math.pow(10,k.oom),k.min=Math.floor(k.low/k.step)*k.step,k.max=Math.ceil(k.high/k.step)*k.step,k.range=k.max-k.min,k.numberOfSteps=Math.round(k.range/k.step);var l=c.projectLength(a,k.step,k),m=l=d)k.step=1;else if(e&&n=d)k.step=n;else for(;;){if(m&&c.projectLength(a,k.step,k)<=d)k.step*=2;else{if(m||!(c.projectLength(a,k.step/2,k)>=d))break;if(k.step/=2,e&&k.step%1!==0){k.step*=2;break}}if(j++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}var o=2.221e-16;for(k.step=Math.max(k.step,o),h=k.min,i=k.max;h+k.step<=k.low;)h=f(h,k.step);for(;i-k.step>=k.high;)i=f(i,-k.step);k.min=h,k.max=i,k.range=k.max-k.min;var p=[];for(g=k.min;g<=k.max;g=f(g,k.step)){var q=c.roundWithPrecision(g);q!==p[p.length-1]&&p.push(q)}return k.values=p,k},c.polarToCartesian=function(a,b,c,d){var e=(d-90)*Math.PI/180;return{x:a+c*Math.cos(e),y:b+c*Math.sin(e)}},c.createChartRect=function(a,b,d){var e=!(!b.axisX&&!b.axisY),f=e?b.axisY.offset:0,g=e?b.axisX.offset:0,h=a.width()||c.quantity(b.width).value||0,i=a.height()||c.quantity(b.height).value||0,j=c.normalizePadding(b.chartPadding,d);h=Math.max(h,f+j.left+j.right),i=Math.max(i,g+j.top+j.bottom);var k={padding:j,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}};return e?("start"===b.axisX.position?(k.y2=j.top+g,k.y1=Math.max(i-j.bottom,k.y2+1)):(k.y2=j.top,k.y1=Math.max(i-j.bottom-g,k.y2+1)),"start"===b.axisY.position?(k.x1=j.left+f,k.x2=Math.max(h-j.right,k.x1+1)):(k.x1=j.left,k.x2=Math.max(h-j.right-f,k.x1+1))):(k.x1=j.left,k.x2=Math.max(h-j.right,k.x1+1),k.y2=j.top,k.y1=Math.max(i-j.bottom,k.y2+1)),k},c.createGrid=function(a,b,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a,j[d.units.pos+"2"]=a,j[d.counterUnits.pos+"1"]=e,j[d.counterUnits.pos+"2"]=e+f;var k=g.elem("line",j,h.join(" "));i.emit("draw",c.extend({type:"grid",axis:d,index:b,group:g,element:k},j))},c.createGridBackground=function(a,b,c,d){var e=a.elem("rect",{x:b.x1,y:b.y2,width:b.width(),height:b.height()},c,!0);d.emit("draw",{type:"gridBackground",group:a,element:e})},c.createLabel=function(a,d,e,f,g,h,i,j,k,l,m){var n,o={};if(o[g.units.pos]=a+i[g.units.pos],o[g.counterUnits.pos]=i[g.counterUnits.pos],o[g.units.len]=d,o[g.counterUnits.len]=Math.max(0,h-10),l){var p=b.createElement("span");p.className=k.join(" "),p.setAttribute("xmlns",c.namespaces.xhtml),p.innerText=f[e],p.style[g.units.len]=Math.round(o[g.units.len])+"px",p.style[g.counterUnits.len]=Math.round(o[g.counterUnits.len])+"px",n=j.foreignObject(p,c.extend({style:"overflow: visible;"},o))}else n=j.elem("text",o,k.join(" ")).text(f[e]);m.emit("draw",c.extend({type:"label",axis:g,index:e,group:j,element:n,text:f[e]},o))},c.getSeriesOption=function(a,b,c){if(a.name&&b.series&&b.series[a.name]){var d=b.series[a.name];return d.hasOwnProperty(c)?d[c]:b[c]}return b[c]},c.optionsProvider=function(b,d,e){function f(b){var f=h;if(h=c.extend({},j),d)for(i=0;i=2&&a[h]<=a[h-2]&&(g=!0),g&&(f.push({pathCoordinates:[],valueData:[]}),g=!1),f[f.length-1].pathCoordinates.push(a[h],a[h+1]),f[f.length-1].valueData.push(b[h/2]));return f}}(window,document,a),function(a,b,c){"use strict";c.Interpolation={},c.Interpolation.none=function(a){var b={fillHoles:!1};return a=c.extend({},b,a),function(b,d){for(var e=new c.Svg.Path,f=!0,g=0;g1){var i=[];return h.forEach(function(a){i.push(f(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(i)}if(b=h[0].pathCoordinates,g=h[0].valueData,b.length<=4)return c.Interpolation.none()(b,g);for(var j,k=(new c.Svg.Path).move(b[0],b[1],!1,g[0]),l=0,m=b.length;m-2*!j>l;l+=2){var n=[{x:+b[l-2],y:+b[l-1]},{x:+b[l],y:+b[l+1]},{x:+b[l+2],y:+b[l+3]},{x:+b[l+4],y:+b[l+5]}];j?l?m-4===l?n[3]={x:+b[0],y:+b[1]}:m-2===l&&(n[2]={x:+b[0],y:+b[1]},n[3]={x:+b[2],y:+b[3]}):n[0]={x:+b[m-2],y:+b[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+b[l],y:+b[l+1]}),k.curve(d*(-n[0].x+6*n[1].x+n[2].x)/6+e*n[2].x,d*(-n[0].y+6*n[1].y+n[2].y)/6+e*n[2].y,d*(n[1].x+6*n[2].x-n[3].x)/6+e*n[2].x,d*(n[1].y+6*n[2].y-n[3].y)/6+e*n[2].y,n[2].x,n[2].y,!1,g[(l+2)/2])}return k}return c.Interpolation.none()([])}},c.Interpolation.monotoneCubic=function(a){var b={fillHoles:!1};return a=c.extend({},b,a),function d(b,e){var f=c.splitIntoSegments(b,e,{fillHoles:a.fillHoles,increasingX:!0});if(f.length){if(f.length>1){var g=[];return f.forEach(function(a){g.push(d(a.pathCoordinates,a.valueData))}),c.Svg.Path.join(g)}if(b=f[0].pathCoordinates,e=f[0].valueData,b.length<=4)return c.Interpolation.none()(b,e);var h,i,j=[],k=[],l=b.length/2,m=[],n=[],o=[],p=[];for(h=0;h0!=n[h]>0?m[h]=0:(m[h]=3*(p[h-1]+p[h])/((2*p[h]+p[h-1])/n[h-1]+(p[h]+2*p[h-1])/n[h]),isFinite(m[h])||(m[h]=0));for(i=(new c.Svg.Path).move(j[0],k[0],!1,e[0]),h=0;h1}).map(function(a){var b=a.pathElements[0],c=a.pathElements[a.pathElements.length-1];return a.clone(!0).position(0).remove(1).move(b.x,r).line(b.x,b.y).position(a.pathElements.length+1).line(c.x,r)}).forEach(function(c){var h=i.elem("path",{d:c.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:b.normalized.series[g],path:c.clone(),series:f,seriesIndex:g,axisX:d,axisY:e,chartRect:j,index:g,group:i,element:h})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:e.bounds,chartRect:j,axisX:d,axisY:e,svg:this.svg,options:a})}function e(a,b,d,e){c.Line["super"].constructor.call(this,a,b,f,c.extend({},f,d),e)}var f={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,type:void 0},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,type:void 0,scaleMinSpace:20,onlyInteger:!1},width:void 0,height:void 0,showLine:!0,showPoint:!0,showArea:!1,areaBase:0,lineSmooth:!0,showGridBackground:!1,low:void 0,high:void 0,chartPadding:{top:15,right:15,bottom:5,left:10},fullWidth:!1,reverseData:!1,classNames:{chart:"ct-chart-line",label:"ct-label",labelGroup:"ct-labels",series:"ct-series",line:"ct-line",point:"ct-point",area:"ct-area",grid:"ct-grid",gridGroup:"ct-grids",gridBackground:"ct-grid-background",vertical:"ct-vertical",horizontal:"ct-horizontal",start:"ct-start",end:"ct-end"}};c.Line=c.Base.extend({constructor:e,createChart:d})}(window,document,a),function(a,b,c){"use strict";function d(a){var b,d;a.distributeSeries?(b=c.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),b.normalized.series=b.normalized.series.map(function(a){return[a]})):b=c.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=c.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var e=this.svg.elem("g").addClass(a.classNames.gridGroup),g=this.svg.elem("g"),h=this.svg.elem("g").addClass(a.classNames.labelGroup);if(a.stackBars&&0!==b.normalized.series.length){var i=c.serialMap(b.normalized.series,function(){ return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+(b&&b.x)||0,y:a.y+(b&&b.y)||0}},{x:0,y:0})});d=c.getHighLow([i],a,a.horizontalBars?"x":"y")}else d=c.getHighLow(b.normalized.series,a,a.horizontalBars?"x":"y");d.high=+a.high||(0===a.high?0:d.high),d.low=+a.low||(0===a.low?0:d.low);var j,k,l,m,n,o=c.createChartRect(this.svg,a,f.padding);k=a.distributeSeries&&a.stackBars?b.normalized.labels.slice(0,1):b.normalized.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new c.AutoScaleAxis(c.Axis.units.x,b.normalized.series,o,c.extend({},a.axisX,{highLow:d,referenceValue:0})):a.axisX.type.call(c,c.Axis.units.x,b.normalized.series,o,c.extend({},a.axisX,{highLow:d,referenceValue:0})),l=n=void 0===a.axisY.type?new c.StepAxis(c.Axis.units.y,b.normalized.series,o,{ticks:k}):a.axisY.type.call(c,c.Axis.units.y,b.normalized.series,o,a.axisY)):(l=m=void 0===a.axisX.type?new c.StepAxis(c.Axis.units.x,b.normalized.series,o,{ticks:k}):a.axisX.type.call(c,c.Axis.units.x,b.normalized.series,o,a.axisX),j=n=void 0===a.axisY.type?new c.AutoScaleAxis(c.Axis.units.y,b.normalized.series,o,c.extend({},a.axisY,{highLow:d,referenceValue:0})):a.axisY.type.call(c,c.Axis.units.y,b.normalized.series,o,c.extend({},a.axisY,{highLow:d,referenceValue:0})));var p=a.horizontalBars?o.x1+j.projectValue(0):o.y1-j.projectValue(0),q=[];l.createGridAndLabels(e,h,this.supportsForeignObject,a,this.eventEmitter),j.createGridAndLabels(e,h,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&c.createGridBackground(e,o,a.classNames.gridBackground,this.eventEmitter),b.raw.series.forEach(function(d,e){var f,h,i=e-(b.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/b.normalized.series.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/b.normalized.series[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":d.name,"ct:meta":c.serialize(d.meta)}),h.addClass([a.classNames.series,d.className||a.classNames.series+"-"+c.alphaNumerate(e)].join(" ")),b.normalized.series[e].forEach(function(g,k){var r,s,t,u;if(u=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,r=a.horizontalBars?{x:o.x1+j.projectValue(g&&g.x?g.x:0,k,b.normalized.series[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,b.normalized.series[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,b.normalized.series[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,b.normalized.series[e])},l instanceof c.StepAxis&&(l.options.stretch||(r[l.units.pos]+=f*(a.horizontalBars?-1:1)),r[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1)),t=q[k]||p,q[k]=t-(p-r[l.counterUnits.pos]),void 0!==g){var v={};v[l.units.pos+"1"]=r[l.units.pos],v[l.units.pos+"2"]=r[l.units.pos],!a.stackBars||"accumulate"!==a.stackMode&&a.stackMode?(v[l.counterUnits.pos+"1"]=p,v[l.counterUnits.pos+"2"]=r[l.counterUnits.pos]):(v[l.counterUnits.pos+"1"]=t,v[l.counterUnits.pos+"2"]=q[k]),v.x1=Math.min(Math.max(v.x1,o.x1),o.x2),v.x2=Math.min(Math.max(v.x2,o.x1),o.x2),v.y1=Math.min(Math.max(v.y1,o.y2),o.y1),v.y2=Math.min(Math.max(v.y2,o.y2),o.y1);var w=c.getMetaData(d,k);s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(c.isNumeric).join(","),"ct:meta":c.serialize(w)}),this.eventEmitter.emit("draw",c.extend({type:"bar",value:g,index:k,meta:w,series:d,seriesIndex:e,axisX:m,axisY:n,chartRect:o,group:h,element:s},v))}}.bind(this))}.bind(this)),this.eventEmitter.emit("created",{bounds:j.bounds,chartRect:o,axisX:m,axisY:n,svg:this.svg,options:a})}function e(a,b,d,e){c.Bar["super"].constructor.call(this,a,b,f,c.extend({},f,d),e)}var f={axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:c.noop,scaleMinSpace:20,onlyInteger:!1},width:void 0,height:void 0,high:void 0,low:void 0,referenceValue:0,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!1,showGridBackground:!1,classNames:{chart:"ct-chart-bar",horizontalBars:"ct-horizontal-bars",label:"ct-label",labelGroup:"ct-labels",series:"ct-series",bar:"ct-bar",grid:"ct-grid",gridGroup:"ct-grids",gridBackground:"ct-grid-background",vertical:"ct-vertical",horizontal:"ct-horizontal",start:"ct-start",end:"ct-end"}};c.Bar=c.Base.extend({constructor:e,createChart:d})}(window,document,a),function(a,b,c){"use strict";function d(a,b,c){var d=b.x>a.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function e(a){var b,e,f,h,i,j=c.normalizeData(this.data),k=[],l=a.startAngle;this.svg=c.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),e=c.createChartRect(this.svg,a,g.padding),f=Math.min(e.width()/2,e.height()/2),i=a.total||j.normalized.series.reduce(function(a,b){return a+b},0);var m=c.quantity(a.donutWidth);"%"===m.unit&&(m.value*=f/100),f-=a.donut&&!a.donutSolid?m.value/2:0,h="outside"===a.labelPosition||a.donut&&!a.donutSolid?f:"center"===a.labelPosition?0:a.donutSolid?f-m.value/2:f/2,h+=a.labelOffset;var n={x:e.x1+e.width()/2,y:e.y2+e.height()/2},o=1===j.raw.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;j.raw.series.forEach(function(a,b){k[b]=this.svg.elem("g",null,null)}.bind(this)),a.showLabel&&(b=this.svg.elem("g",null,null)),j.raw.series.forEach(function(e,g){if(0!==j.normalized.series[g]||!a.ignoreEmptyValues){k[g].attr({"ct:series-name":e.name}),k[g].addClass([a.classNames.series,e.className||a.classNames.series+"-"+c.alphaNumerate(g)].join(" "));var p=i>0?l+j.normalized.series[g]/i*360:0,q=Math.max(0,l-(0===g||o?0:.2));p-q>=359.99&&(p=q+359.99);var r,s,t,u=c.polarToCartesian(n.x,n.y,f,q),v=c.polarToCartesian(n.x,n.y,f,p),w=new c.Svg.Path(!a.donut||a.donutSolid).move(v.x,v.y).arc(f,f,0,p-l>180,0,u.x,u.y);a.donut?a.donutSolid&&(t=f-m.value,r=c.polarToCartesian(n.x,n.y,t,l-(0===g||o?0:.2)),s=c.polarToCartesian(n.x,n.y,t,p),w.line(r.x,r.y),w.arc(t,t,0,p-l>180,1,s.x,s.y)):w.line(n.x,n.y);var x=a.classNames.slicePie;a.donut&&(x=a.classNames.sliceDonut,a.donutSolid&&(x=a.classNames.sliceDonutSolid));var y=k[g].elem("path",{d:w.stringify()},x);if(y.attr({"ct:value":j.normalized.series[g],"ct:meta":c.serialize(e.meta)}),a.donut&&!a.donutSolid&&(y._node.style.strokeWidth=m.value+"px"),this.eventEmitter.emit("draw",{type:"slice",value:j.normalized.series[g],totalDataSum:i,index:g,meta:e.meta,series:e,group:k[g],element:y,path:w.clone(),center:n,radius:f,startAngle:l,endAngle:p}),a.showLabel){var z;z=1===j.raw.series.length?{x:n.x,y:n.y}:c.polarToCartesian(n.x,n.y,h,l+(p-l)/2);var A;A=j.normalized.labels&&!c.isFalseyButZero(j.normalized.labels[g])?j.normalized.labels[g]:j.normalized.series[g];var B=a.labelInterpolationFnc(A,g);if(B||0===B){var C=b.elem("text",{dx:z.x,dy:z.y,"text-anchor":d(n,z,a.labelDirection)},a.classNames.label).text(""+B);this.eventEmitter.emit("draw",{type:"label",index:g,group:b,element:C,text:""+B,x:z.x,y:z.y})}}l=p}}.bind(this)),this.eventEmitter.emit("created",{chartRect:e,svg:this.svg,options:a})}function f(a,b,d,e){c.Pie["super"].constructor.call(this,a,b,g,c.extend({},g,d),e)}var g={width:void 0,height:void 0,chartPadding:5,classNames:{chartPie:"ct-chart-pie",chartDonut:"ct-chart-donut",series:"ct-series",slicePie:"ct-slice-pie",sliceDonut:"ct-slice-donut",sliceDonutSolid:"ct-slice-donut-solid",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutSolid:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelPosition:"inside",labelInterpolationFnc:c.noop,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1};c.Pie=c.Base.extend({constructor:f,createChart:e,determineAnchorPosition:d})}(window,document,a),a}); //# sourceMappingURL=chartist.min.js.mapSABnzbd-2.3.2/interfaces/Config/templates/staticcfg/js/filesize.min.js0000644000000000000000000000366213217005257024003 0ustar 00000000000000/* 2017 Jason Mulligan @version 3.5.11 */ "use strict";!function(i){function e(i){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=[],d=0,r=void 0,a=void 0,s=void 0,f=void 0,u=void 0,l=void 0,v=void 0,B=void 0,c=void 0,p=void 0,y=void 0,m=void 0,x=void 0,g=void 0;if(isNaN(i))throw new Error("Invalid arguments");return s=!0===e.bits,y=!0===e.unix,a=e.base||2,p=void 0!==e.round?e.round:y?1:2,m=void 0!==e.spacer?e.spacer:y?"":" ",g=e.symbols||e.suffixes||{},x=2===a?e.standard||"jedec":"jedec",c=e.output||"string",u=!0===e.fullform,l=e.fullforms instanceof Array?e.fullforms:[],r=void 0!==e.exponent?e.exponent:-1,B=Number(i),v=B<0,f=a>2?1e3:1024,v&&(B=-B),(-1===r||isNaN(r))&&(r=Math.floor(Math.log(B)/Math.log(f)))<0&&(r=0),r>8&&(r=8),0===B?(n[0]=0,n[1]=y?"":t[x][s?"bits":"bytes"][r]):(d=B/(2===a?Math.pow(2,10*r):Math.pow(1e3,r)),s&&(d*=8)>=f&&r<8&&(d/=f,r++),n[0]=Number(d.toFixed(r>0?p:0)),n[1]=10===a&&1===r?s?"kb":"kB":t[x][s?"bits":"bytes"][r],y&&(n[1]="jedec"===x?n[1].charAt(0):r>0?n[1].replace(/B$/,""):n[1],o.test(n[1])&&(n[0]=Math.floor(n[0]),n[1]=""))),v&&(n[0]=-n[0]),n[1]=g[n[1]]||n[1],"array"===c?n:"exponent"===c?r:"object"===c?{value:n[0],suffix:n[1],symbol:n[1]}:(u&&(n[1]=l[r]?l[r]:b[x][r]+(s?"bit":"byte")+(1===n[0]?"":"s")),n.join(m))}var o=/^(b|B)$/,t={iec:{bits:["b","Kib","Mib","Gib","Tib","Pib","Eib","Zib","Yib"],bytes:["B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"]},jedec:{bits:["b","Kb","Mb","Gb","Tb","Pb","Eb","Zb","Yb"],bytes:["B","KB","MB","GB","TB","PB","EB","ZB","YB"]}},b={iec:["","kibi","mebi","gibi","tebi","pebi","exbi","zebi","yobi"],jedec:["","kilo","mega","giga","tera","peta","exa","zetta","yotta"]};e.partial=function(i){return function(o){return e(o,i)}},"undefined"!=typeof exports?module.exports=e:"function"==typeof define&&define.amd?define(function(){return e}):i.filesize=e}("undefined"!=typeof window?window:global); //# sourceMappingURL=filesize.min.js.mapSABnzbd-2.3.2/interfaces/Config/templates/staticcfg/js/jquery-3.2.1.min.js0000644000000000000000000025120313217005257024143 0ustar 00000000000000/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */ !function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S), a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b), null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("
  • $T('menu-queue')
  • $T('menu-history')
  • $T('warnings')
SABnzbd-2.3.2/interfaces/Glitter/templates/nzo.tmpl0000644000000000000000000000000713217005256020364 0ustar 00000000000000  SABnzbd-2.3.2/interfaces/Glitter/templates/queue.tmpl0000644000000000000000000000300313217005256020701 0ustar 00000000000000 $T('post-Paused') ($timeString) - $sizeleft $T('Glitter-left') - SABnzbd SABnzbd $speed KB/s - $sizeleft $T('Glitter-left') - SABnzbd |||SABnzbd-2.3.2/interfaces/Glitter/templates/status.tmpl0000644000000000000000000000000713217005256021101 0ustar 00000000000000  SABnzbd-2.3.2/interfaces/Glitter/templates/static/bootstrap/css/bootstrap.min.css0000644000000000000000000045433013217005256026301 0ustar 00000000000000/*! * Bootstrap v3.3.5 (http://getbootstrap.com) * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * * SABnzbd EDIT: We use the Glyphicons of v3.0.2 because the new ones are not sharp on Firefox and Chrome on Windows (Sep 2015). * For example compare the icons in the config (that uses the new ones), with the Glitter icons. * *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}} @font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url(data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAFr8ABEAAAAAoRQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABgAAAABwAAAAcaPfj5EdERUYAAAGcAAAAHgAAACABCAAET1MvMgAAAbwAAABDAAAAYGenS4RjbWFwAAACAAAAARcAAAJq4khMF2N2dCAAAAMYAAAACAAAAAgAKAOHZnBnbQAAAyAAAAGxAAACZVO0L6dnYXNwAAAE1AAAAAgAAAAIAAAAEGdseWYAAATcAABN8wAAiRgqz6OJaGVhZAAAUtAAAAA0AAAANgEEa5xoaGVhAABTBAAAABwAAAAkCjIED2htdHgAAFMgAAABFAAAAvTBvxGPbG9jYQAAVDQAAAGrAAABuDKVVHptYXhwAABV4AAAACAAAAAgAgQBoG5hbWUAAFYAAAABgwAAA3zUvpnzcG9zdAAAV4QAAAM+AAAIhMxBkFZwcmVwAABaxAAAAC4AAAAusPIrFHdlYmYAAFr0AAAABgAAAAZh/lI3AAAAAQAAAADMPaLPAAAAAM5dLpcAAAAAzl0SfXjaY2BkYGDgA2IJBhBgYmAEwltAzALmMQAADagBDQAAeNpjYGZpZJzAwMrAwszDdIGBgSEKQjMuYTBi2gHkA6Wwg1DvcD8GBwbeRwzMB/4LANVJMNQAhRmRlCgwMAIAC2EJ1gB42s2RPUsDQRCGZ5Nc5ERjCAoeiDNYGKKFadOdjSaFErC6KkEkGLAIVqZLmy6NBDt/gKV/Jld485rCykptbNY1BxZXWVj4wnwtM8/ALBHlKbUtMs6TuXCVWdQF03TxlELyqOSyVRLap3tZlgPpyMNOZddU/eqa5tXXQGva0JZG2tW+DnWsU/gIUEMDR2ghQh9DjHGLu2ey9nvTgrfneJThkXpaVtG6htp2vHMd6EgnMChDUEeIJtroYoARJpgueMZ+2LmNbU+XknnymFw+5eONWWnmSyCbUpEVKQrxJ7/zG7/yC4Nv+JqvuMdd7nDEZ3zCx3zI4Xac3uEvZYr0AzU553LZhvQLUhU8+tcqZh/WfzP1BXUjZUgAAAAAjwAoAvh42l1Ru05bQRDdDQ8DgcTYIDnaFLOZkMZ7oQUJxNWNYmQ7heUIaTdykYtxAR9AgUQN2q8ZoKGkSJsGIRdIfEI+IRIza4iiNDs7s3POmTNLypGqd+lrz1PnJJDC3QbNNv1OSLWzAPek6+uNjLSDB1psZvTKdfv+Cwab0ZQ7agDlPW8pDxlNO4FatKf+0fwKhvv8H/M7GLQ00/TUOgnpIQTmm3FLg+8ZzbrLD/qC1eFiMDCkmKbiLj+mUv63NOdqy7C1kdG8gzMR+ck0QFNrbQSa/tQh1fNxFEuQy6axNpiYsv4kE8GFyXRVU7XM+NrBXbKz6GCDKs2BB9jDVnkMHg4PJhTStyTKLA0R9mKrxAgRkxwKOeXcyf6kQPlIEsa8SUo744a1BsaR18CgNk+z/zybTW1vHcL4WRzBd78ZSzr4yIbaGBFiO2IpgAlEQkZV+YYaz70sBuRS+89AlIDl8Y9/nQi07thEPJe1dQ4xVgh6ftvc8suKu1a5zotCd2+qaqjSKc37Xs6+xwOeHgvDQWPBm8/7/kqB+jwsrjRoDgRDejd6/6K16oirvBc+sifTv7FaAAAAAAEAAf//AA942r29B4Ab5ZUAPN/MSKMujaTRSNqVVmUlbZW80mrl9RYbV9yNDS50g4CAKabEGDAGTAskhgWCCTEJDhzgUEeyCUnO3CUkcEpR2hmHcBeONI6Ecgn4Sox3/L/3fdKuthjC3f//XkuaJs1773vf+14fjufaOI58RohwAidx6RLhMoNlSeTfy5aMhn8dLAs8bHIlAQ8b8HBZMgpHB8sEj+fkqJzIyfE2Mkd/+89/FiJH32zjf8YRrsgVxWXiMk7lWjmNy2j2nEaqmjVLNH9G8xzSDFnNXdWkbClAOrkZPZ58NFVQ5ZxcUKWoElWllByXpVShSIQXdr5QgRcR9NH65uFJB/RRehmgwcE/el8rt4QrWziuE28u0ZsbsmXCWTr3zSGCuZNotoxmOaTxWc1c1cRs2WzBU2bJ3Fm2mHHTwpk7S3YKXYBE5fofGSFdZETfrB8c39I3kxGKs0H8gvgsV+C2cFo2o7VVy21Z/Km2tJnCEaVwtGQ1Q0ZrzmnGqhbMakpGs1bLihUvVFwI2cyMVqCQxaqlUEsWPl2lbtKpubJauqo5s6V+0lmKFWS3JvVr3XLZGsn29/cjFQu53kK8kOsr9OWyqk+N96b5eMzBS1EpalTgLSzmssN8PmeUjPFYKk1SxeLlhteLtyeWfnb/B5sHjc/nli0J+/vnz/aQ64r6QSPZBe/mGf3zckpoybLcsy0bNz1Rvbp1ro0cLmbyxSdO3fniBRcV1s8IeLtOHS6m+4pLrprb6QzOWJd/+qLPfjX91FYOx6RCRsRl/AHgLzflBaFKNDFTMrCRB6JWhFuObkNy4vCRYx+QLvEl8QTOx7VwmpDRnFXNAl9RMyU/fKVkEWR3yebu75/RI3h9uWi2L9+bjMekNInHjIpXdRDH5Sv597c++eTWdFfX85d+6TV+7ink/VVXPH3t1mccG6/+5YMBm2MTJ8K9iqIGvCIC31s4O8fliVogCdlsgFGuANQfrSJd+kF+Pb8eRruriAf1zRW6d3j0Mf403Ua6RvfC7wjHPjz2ofii+CLHc0bOxXFSAtiZwKvQ15shyZhkJ8v/7dRD/PmH1h46125/0NnqtG/+t5PYgdPtKceDdjtX49/6v546P2uixpm5HFc2Ij9LVU2AaWTJaKZDQMqyYELOEQzAuCYBN01GYFwrJa4cJTJMp3xUFjUE9uibQFpt9PXR14tFPom/7+BMMF+e4yIclwyTwjDJywk5KTmIWtvrTUoGB1HgmFFs/dzKE4AYc5asXOeW71i5cI3DMuqyOGD/85e2B5WzO/gzd4/+t0sNXtFXaA+oJxWEyy1W4buCxzK6UvYHOKCOeuxd8fvig5yHa+I2cGUHYuTOaGpVa2KM0ZzRyCFNqWqKC2WDZoA5AOweUGT3PoF3uVvVfs0gA+dzJbcDpoC5X1NlzdWvNbn3EU4ywPkZPW4XIKR4JeLzOokxliLA7rzLF+lzJSMqaQZWa15BuiTpEpPXpB+8+q7KzS8R93e/q79P3sNz+u8rd12tH4STl0gS6VrBX6z/+aXvwhWUP2GerxefE+dzAU7hiBbMaNwhzVGF/6UmxtK9w3yYqPDGK16HIKXF4sxTr776mq4Z12397Pq+edfcsnd4+IlbrpknuOZsWdMtLp6/4ESxe82WOf3X3HhD+ZRTyjfceA3Q6tg3uUXi/TD2Fs4GLBb15DxR4jETj1A4kfzbvfy95DV9xz36jfqOe7/ICxEqiv6kzyYe/T3yj/BJ+bLxN3ycn9PsIH6pGBKzY1MKJlLjr3tUqaCmCvGUNPU+876/+DvfW/Ldd5avmOaO/FV3/fYLO//whX/+Z66Rdz3Ay3mSjyWHSG9f1hciXmNcIQoZSczW/kebnSAjdxNSvD9X2aZp2yq5+4v6sbs5nI/0+8voumTlnPA7KnBNCxfnUlwnl4EZoXFlDjlIrJb8ERCUUkaL5TRTVWvNataMlsxptqrWltWcGa0jp7mqWldW82S0dE7zVrUZWcQ/nM0hOYjWS8dRrO4z2VzeVjWriS4UUfvMdlnBXX9Va4Z3xpWhrBap7mtt65qBpyKuUhSuTLR39+CuUC3lUVDZrCCogk39/ZpTLjWHUGD10PUyH89PeqEUhFkaJdOcE7WP9hfH/oH4Gd1LXwfGD4rLGi9BWQrC6ui2sSOUlGNroxNomOFmc3O5sh2p15UDtJFkoYw2SEnTC7wxh9LDRddHP7y7ShFAHIjWXtVmZksnUL4B+dAHEtinyDCm0VgyQCbuk084HwIuUEIhRd+M7+Pb/Prjnck2HOYvadgZffF4ZziQnpNxX8mdxV3G3cDdDWs1pUJp8OIc0qHUW8wiJUrLtuWQFqX5V8F+d6Z0+hdgv7VaOvmWLFBnBKlTciHTmYH52rKUQjNAUs1ZBdv91dKJ6/HTVTobjm2+EbYvrJa2fi6bLd1DKYdzYYCw2dBJYkk5//H7JP//7fUhpYIEO84bGfm/nc+O7ZHHpts8+p//1wtg3a3Li8YxXlvj8UHK4710+i/Lac1VbT6OqnY6jql2Mozo2RNGVD3OiJY2Tj96Xh/s9sHhJOwalcnncTSQ76nsizLqf9z+J1ObP4A7o/PxffrtRpqPf/tTUBRleIiLiR+IHZyB42BxSJFUiDwqZA+Ofu0n5BX9dKEXtn6K113EXSQuFBeCnMbrCmaimolkJheRoP7WQRIkwYP6W/QNPoYn7h/Ea2CtmqAbpLgXJmgHoBbEc1qoqkWz5eYQqjnNSdB4Qs24GWoB/bqmP7Q16A9JEFjhrJaoapFsOZHESxNx+FYygZvJZvhWYkzLaIeRToKWUeZ9ILL7tYSsufu1AGgdqivYoHWobtA6XP2lEGgf+ziD4sdzTXLZGyD9/Z+gewggz3NKTokr8fzH6iELixUQ9Z+gjegb8CKU7nXafZnSroU7YzrNKjJVs4rWNKvnUbNqDn2MbvU86lbN4U/UrgRYxqZitnXnOGaoNZD3a4jtvEZ/VfLBVSbSuZwi9hJxvQSIUV2RU8UHQX9ogtV+AYeGI5oBXXRdkqpliRpzEhhzmuQq2QAjT7Vs8+BBG9hRaDKVbBIMkupvjgPgVDNzFxTQZr0ALBgNqbzPDRoaH0vzhE1g1HfpBFZ/8cQF246Qc45su+CJX5y2+9V3X919Gvl1SCni7CjiAvUCaRt+vFDZWjpypLS1Unh8WH/thS1wFVxMbONrFqy7RY6AXCqN6TEzuLKIK47JlssRzZXRRMQHkQAqgDGoWRk6zmpJptKmABY2AeO4/lcE46SrAkNfIWigkMO6DS1vUBRWId2CXJO4S9zFLeJO4s7hkAlWVbWlGa0PqLeaUu/Eqnaiq7Qc7gEL2hqg04kcqCrWIWD75fI+p5LrR1ZodZcCGTAsS6uA5UsSKDDaUnmfEE0twLN97lLnCcjwHm8L72shkk8tqD7YzGVn832zidpXSBX6YDPfm+GTGVJIpqRUEjbjMSdvdJKUUVIlI2waUClUvMZYMmh8gHf4hVXdg7caunsMybZYUyZpTGcMt82csUrwO8mXDIYvEZcqrOoavM3QPcPIrjBkuwy3DqRXCQE7/4CRXLC9vB3+8xui7UljT5fhtoH0SUIQThkMD/D2oHBS19Bthq4e/HJzd9KY6zDcNitzkhBwsJ93BISTMrNuM2TSxuSMwPrt29dv2L4dZKHEFY8dEzWDF/T+cQ20wN3BlaM411rB2p/Rm4WlIpUpd2T7cqAuNFVBxUSlwtEFxzMZWFmoeR88hKtOq6uUwHmY1dpQMy0n2qiE4oCh21woj7QZoKW6Sj2w1Z3VequaPVvu7cGLej1wUa8L9UwQiugQoE4UXETGVpKG5cQDaifbQlbywAvVTU9tu+i0EM9AO+lqHyAei9Nh/egtq6Mo3DLQPjq/faBIZQzyGZM2IslanMX2gYF2+F7W6nAcvRSZr31wsJ0/MDqfPwCW8kf72Sazl+DPoIi/Bhukiyubqb4OfA/6ufkQ6uomqmcjlYDpSwYTCB5CJ6uZxOtOF36Ev6WiH8Q/fgN/y+i20b0oR/j1yO8oAN8GOeHgZC7GlcFY6iTI9SDtjNWykSDBjCaQCB42m6hOOkYRIpOiw0r+hYw4rEeftTr49aQrIG63OnTb6BmAnuBG3FHGipwoPi0+DXPYAzywg0Mb3FnVvChky6oXb6MqMC4eHHJqGAIEdhg1V8kLCI5fFICLVBdObpj3aDSWvHaQUxbB4YGZVZJV2DGLTrR1uZLXCXsSZ3fhKQ+eMhLZVhPE7taI6HbxYqTVXRPAHpQQiriHuMl84t6zR39fP6C/7/uQrP3wQ/3JRSAyvtF4Ys8e/iz9yQ/x9KgOJD1IbQX+2EMcZ/ACTVFepWtWlpRDjMGicmao48FJHQ/EjCyMcqwmreIkJ8AfiQpxwZMT4kXy3M+VR7w/I8+NvtX+QVvPm01Piho6VD5aRdeCw8zvw9d0dHbPJVzZivdkdwMThGTHRWVZlPDWIsdEvx3oaKGysiSJIKl4M0gquwzylXrF0AuCfkqAiNpe5E/6Gyg/9Tdg6zfPPUf9eCBC0Y9XKcI4A7+Cff8cQKFyYe7cmgbpoXPZAAPbQgdWrmoyW0hBmWx2lRTYAsUxgkuqLLv320W3SnWDZlkL92uKe7/N4PGF6JiqHlhzicnMBWsrau8wnw3zdCki9ZEUqLAXyFl73jj8xp6z2MfpH5CTP/hAf3rVrsquI6ThBHzwvP70B3hep9MVmHYizwa5jXWerbFoUwOLIiZg4/rH+LIZMQG+3I986UVM/LKm9GtwBJnTRzHxOBETo8RRPWh6lhSaYCLH5ePx5MojR3Ydnyv1cxgulEn4MZ+CjfNy7TUPr71aMsggX2Ei8oCUkin50Py2W4AXiBOXqLzsibpztQnvyanRQk6IVoTIPxEQdjusjkolS7qylY2jjwTIv6Do0hMw88lbsM4exls20lHh/NzChrmPdAxQOgKv2saoFwTqyTYgjmi2CD7/2FSmxPKpU4jlqekkEZjdhuOR6kMyi7RPJhXZD6P+9FNw/k5yTwW4t643NXNrOHQ1w/jKGS0AcIYonAC301WyMH4NA5wWhMsgerxqAIfZLJcUH677Mo4+4cxeBQ8HZI0C7Q3z6ESOe42RpAsdzVJUlmBVdxC1pijtOqJ/FbSiz116Lxm55yuvgFbE/+RdphptAXUJtKqT8My1p+3mmJ7HUXhdXJS7livLOKYwx3zVsq8F57kvCPPcjnOvbDfgATuHbvIYc1BUNRdj3mC1FAdkXKjKyO5+BPgFyWC1gH4SRfiD7pLZhGj5WmCJiVIRYcbrDOhIZ247wKYgRwtJ9CQLclQCZaYvn4N5GY+lELstr3zlHn3zfZtvLx1ZTEbo5y52mF+Pyt+1eHbVkRIuT/hJj3Gw8hVrfDudL2sVp5kymj+HYi6YxcBEcw4HLZRFiRfJoaiJUvZuzaH+nshSM8d0qGxzeVHhsFbLDrcPtlBpAImHqxsu+QkwNlINLw8s+kMkqiTy7MX8RsItR9+sO4pQDo6/0POErnmmArD/o3uLY7sNMht1IpDZKo5dhOk5rTBih2BUyoYgDpoBpXXQhcud5gCAm/CgA/QYVIK4UgRXNtFhCNKZgX6lgXGjOdfgUQIFh6nooIBsWU26Vm+hysjRbaC9gCSntmuRX98+UFm9ZcvqCigxe+E8/4ddVBuv6QvUFyTAXFbZ2kY0H+UmASx/RkKQvZ5hEuaHSUF2kLRglADtwdu3brviomJ723W3jNx+1alepB8ZGZxhjzYZVp5EDp+0wNLWZllwEpMZTFY9AFzdw53AXcCVM0id4ZyWrGp9dJxDQKa5NXsGV7IY0KazqnW6SlnYGqhqA66Si6oOpXnA2tlOoJHNGmqm0iSZgdkpuTxeAbnbBusdlXXymCUzTCJhoozvp/mYg1c8MnNNIEHRNZGYtO+wglK38/fE+PuddPPcR994+41Hz63YTHtMNvrGrx/fJh4QlFbSdcPPr7ji5zfoB9neVfAF+N5Vo6+SH+OFei++N2zXZHlFXC+8zRlAb+PkqEE2REkBYyYqWAYpMHWZ5Oe1nTsX1f+TERDbFf2phkP13xI2099ycm6OqgqOQyjf5FogBH89UQA7Q0qBmB377QMLLrto3lr2q/3525/7+q19l955b338vi2eI/w3/c0QN0hjV+gpDtd+G/1DHiZ4WmB0PGYYHZdPZUs84VCJc3gYPwdINCEnyNj9wVJSwHhWC2gdEQYNuZfCcqZ03dXSSca7RozkHoDr6JsV8gMA7MlbC5feeU/V9MB3X9xlmmsq/+6tsmnMR66BVJGBmwMAZ5TaJbO5eWD/LeVWEsI4vDRjPhgk7mq5vWcByoxgppzqXMaMlHKiezkei2VKvBGOxEEpzwKaJceJsBetlnoXo89zFRouJUMY/aPVkoCRyRDzkNnRvMlVtTy8u0ppa6fWQd0uc7LlNPW1pGPmzjKxOvEuCVepAN+ZfyJsD1RLySX46SotA0rOzWorq+X+oYUoy06Ci2aEYGXyKv5A72xUfwsJ2V1ua5+J4c5SrAko7PHOpLZqXC6LswbQbxN2zzEbfIG+wuDQnHmU+D1ROZ5Hl0suH0WHOhOOBF4CCEUBVcI8qIfUK4MXsaMgAKK4y64WQFwSFKHwIofR9iYjxaJuo5oWGuMoPLuYVc789LBdGd2LH3gJla01GdsFQgPjigfwHeUpfwB/iV5UrMBWUXgbmbOC4ngzXoQCWrgFhO985ss3j4371PVkM7OAyqK3GUcXlCMllM3SY1R7baWBQ+ZlQNliy6JqizohmClWlDVom/hhC6zXJub1j1dRSJdcGNCQjP39pSaQ1jSkgTEANCOBPCmgmIorDXwq8JmvfeI+RbsytopUKsLbH62CLeHto/7KaadN+0nnNRnjbw/qe1LNq4VKl5cqMzDFFVw/3BKwBme0Uh+ch5p4ZsJ5VV+20NebSsYkAlbu6/wBsOpeC4XXhEP4BkPwLxYnqHs24Xcnh8LhEL7RuQ8SxfDr2n0DIL/ZndUcu7nmzdbtOzOL+tH774f7+wKU56aDIJFDDyoPApLB8Ut2P3jjrUU8kiUvIURWxySINNyHkzT2yOhhgRles8qY1muly4ilqlkmmNMWDj2akonOGAl3iGigNMrJBdDbQMeJysXnhK8UR91F/n2RPHfUD+xXpOTH2D1dK0twPw6gl3uTsAYblQp5ibwUUo6+qYTIAX2BuN0bDnsb1jy04VTQbDZw5QTCCBaShdqMFqGeWqFJ2bJgmWBBtlEUgDP5LDKniflGJOaaNVlx7XOmYsyTB8yFWjxM7KjigS0hTRAySSgME9QZWoiPqgsVUAWA3Y6+mW/jVw2fybss+rDFxc9N8h4LOWzx8Eneahnda8EBgPk6v1Lhf7VtGzkV17GPbvqSxeGw4FstfsbyBUJcgusGnriMZieAmGvPaN2gomVgIhFM/AAsWqrlFuqfbMkAdi2uUoou7aUcoNICw6AF+kudKUAp2pqI0AWjux32WmJxtAi1qFxK94Aw87j3WwPBzAymFNWyHaiPMi3CYu3gnTTpgUMXmtcY472+bF9vMoaK30C78DYqRrtEZ66wpqPSvnpW2mrbBVpScaQyMlIxDq8fHl5PgDp4FSpMpqYF+U7YUbwD7WAKwzUjJIIXDZ9Jdb08HdvnwCaOwYtxnz2nhatl3oaSnWjxTKm1poHmwZKdTaIqDIMSzSdTaQLrXByMHwdxEuJRPXlySftwq+d0cvtqV2eefC3W5g4bjfoNZ+iX+5ttHU4n2VROXzXX19f1pze6182dSzo8aYddeOuoe0aTLShJ5J/ID76gfw94Dv0/36M5DO0wKudx5QhCFq2yT0LHp6Oq9WSYpQscRkdJPATX4EIVhSUL02tAs44ckoFZ6Sgl0jBKPhiY9ihsNPdrHTLsaj3o/AcE8zQ5Ii2k8hjO9OJIhEX4JPFUjmakdMJywVJTQD/lzb7WFvLLrd9WozGrDQjd27nl8ZWVr2248fozH/78sov37t4g5dqEgWY1ZHdKC7UvFM4otJkkwZY7YcvCk+9ZXtl48qk3Fa9bvnojm5PCZVTnjtRGgdAQLYgAB0a8UTTVUhEQzIKnD8kPgKoOwUkEo09VKsuvND1jaVtkNBvI1/norFjAYLjRMmNRvzQvI5w0s9VDBNLfb4qnEjbb0X/qHTT2c/yx52s+ITPw/3au3MTstDJv8OFCYwOOt1GOdwHHW4AbklRAMs0WrU2YKbD2h6ifoeynQRx/EIM4fhrEaYKv+dma5KzifClZQKaWDNRma2li8QibrIlA/hTM/IIal3OSR85FYQdGopPIKrBaQQZTVFCWLl16/fXwOrKLP7Ar61LS0VilqG8uVmLRjFcGde+JJ46++YRwLi6voZRi5o8+my0Ws8Jq3qykQnTtiR77hng3yD7E9w4O1C3Al69S07QRXQvA7WToWg59eiRDoNPs401mggqOy49WEIgxKhJ4E+DPgbjWWmSQ20Eqt2cTQFKVQO4Jx0E9+gTDrshQ92bGUU8rrtz1jDLCT8dQH92CqPN31lGv5Qo0xlK5mvDBCCddAj7tfkgRl6EF9tF+fBci+I7rB2y/Tbf9NHq5nkYv94LKgksKjbZUPnbrb4FVnrTv+YTzE2Ed364cN9Q6Bg45PLapb57u6DTwJmseRtArujMYGAhlMAljKKP1VjEPo5ZrMUQmxog9+U+334hJsZHslcbxqEwYBBbuAuD5i8c29benO/rxeDGMGHafhJf8qWPl04/W8bbHkSJzPmETUTJNm1eAuSOra/gto7kF82n+zOk0f+ZkmltwMc0tKGYR4205jN9cBWLiRtQPyq7IjCzNNCj722aitXPT/yorZLqsj/8bLesBzo9/Qz/LhDn8idufgupHRz7NCBmP7a6NjxG01CDXwc3ilsDKiNZ6kma6pYHqSzNoYDKznK4gGIoHKUpjYJ9etE1I9jjvB48/jmYNzhyc5zhzYM534bZ+cHz+67Y61CgKwBxEOazbxGUfvfW3Cjv4Z0SbyKA08OM8wFflynOoH2tpRptzSJtXpejO6Cn8H3HDsLNHpalo5NPhJ0SK0Scqlb9Vjn/0FjrT+OT1S4tLa74hTXibenO6adYiTDG0+jxUvQarywtrp5mjuRhcSbTXnL7oapmYYgZWS1cL/35LV1fLqLulS7gFzHQPfyfd3wLvpMiSeIWGea4CZTfUZjcs9/UwLs2hmOBzDlXRBVIL/WA2RSgAEMn9miKXPG6quABkZZdHQddEk6x5+6cmzc0mhhTxyFF3TYsPusX1nkDA89Fed7D436RjCUm8e9R/8YrNK1Zs7hIOu4NB91EbvL/3jZsfIsP6m+Sw/hM8twLo9sVjH4rN4oucFzT0oRoGIQZ7C4Wd5X+gE9bEglVNCpDOLiKsIYRV4vzMhu4FSyobJl6qsafFVBJ5iZoXxi9e8/Nrr/vZNYsX/31/vyV27hlXds5+6YGLNj3wwKFd/B+3/fKm7a/+1/1X/NfcuebYpsv2LP38LnrmAWbP12NrCrd4PLLmZZE1X0NkzcOIqqJnTa6BiKEJA0b1Sl4PKEoYQZs2fpaTYxPDZss/0rTJ0TKz/tUjwlqA6bOcKPybwcn5QM/jAG2hEDaiRi+l+UKYqIU0n0r2zSYO8tn5l1x5ZVhZvHLd8tmJFdu/vPKK79243XHaaS7Jl7Y4ebP59ALZdeY3v/aVl89edPeWq6/87G0LNjxYHBCNZ75ww+qLg+cYfUvaFu/szV26a8xWfln8DNfMRWGtXMeVg0gNZxWjAThgKTpgLKqE1PBVS21IDRvGgENhNBs1n1xqiSFBTBgmVkIs1CHK+yKxeKLmegRuE1VpgqJTUBjrJQokZQYUM+Sdx8ilLd/Wf4DGIDncPlB55zH94GPvkP1fIw9doW8if738cuV0dLA/9o7R9G0wEG145fWV3zz2zjsXZclDl8M1/3P55ac0j8dy74e51MyluRNrmMG0iWW0VFUzs9ns0oyAZYZiaa+iI5ErxVzAgkqoFViwZA7CXEr0l0QjfCbHprZqlOLjuOTrqJBhoYUoZqLEHAZAxsDfeso9k5F5InzBBWeFQ+Qz+oOS/8R5a+f1M4xWRdbXMXowDwiRaLLXYybk52Q+GX6Nd6i5eZeM4/UE9QHEcf1vquFlZiPWWsNlPORP/WY0ui+FW9B3gRlVURgvMyC6zwf2PhuvUiTaILyOM1pmPkVSgFvX4Lyy/uhk5NaSJr7vc/rq+xhOaqmO0oLK1xGnnfrv+cId+kn3sdxslpOkcgu4shux8FHrEewbMyvS8R7ShCziZqJFOiWXFyahkco0H+YD2VWYj7xc4mw06kAUWCPMJA4fZpKHDzPmMivoBQWBm/oe9YJWvqf/Ct4r/Gmk7RV25BX9Nf3gKxXqRH1lzOck3AI09gCVWTTQmqPuPkZbgEcZS+RgkQsCf0wBqjD15LBuoxtZpuXqS8m/f7SfvK0vqec11mU9Svqygv5xuxOzsfz0LnIda64eiqrfZfxOtRvRzIEpN9MDtRv6x25KuM+N6SneWi0H5sFIGfR0Yb4L+/XP8b34m3yST47/SoMvbhlyIVCXFs3gVZQvK1xRuIWuly0cV5iUzDY5ua0yfeLurum1t9q9i+Iy+vtcYdwNxZyBjV/ahQt6w/eQzm11nKmvwtCIM/CNDAs0Ocz3jv5YXIYIY3UKeXvKGNEYBkj2XJ05xSwKjcDYz5BJcaw8HoPhGVdaUdXCO8Dr+XGTk3wDBwnuhxkGwtt1vqOwOhjfuWk1lrVa47vodPfqarwTvc+Ee7C4I+g0YhvVadw1nQYVGhQVyM6TdfMomWCmictGXz8ypoUTJ98LNPoWJwl/Fb9O83Mx7Tb1LX7Vn/WHycY/8+tGtT+TjbCFuLmO/UJcLV6F1kzCTApElRQ4SDbqD/+FH1TIqPYSvXT0ZR8hoyUm6wSOF58Rn6G+3Lk048FRxXI1hNo/NeMhUMt42IcZD9R/oWCKLOY7TM12yIGcQKUyrsSFPcQDctazZ4/+nn5Af++OCv1H0xzqB9/ds4espocnwOUEHWI8JwnhcjXAZWdwYV6QfQJcNswMkThYYkQn5ogY+yeDF81Hp4CFRRfTADWVVlkKU01f9Y85wRiFJILVay4UoyKCYVem3FwtqIVUISWlJHUyEGte3bnz1bvugveDO6fA0l4/A+8MJqEGkzwRJncDTJ4xmBzjMDmnwAScJaUmQ7OJeMnu5949fwIk7wEkt+jvkN3Pvns+i6OO06YPbLOLKSSFqjaL6gJRql73stEboHMtXNXCzCUL8A0CfGFcb6K9sN6k5f1msY2G/LhSalZtGLWorHVglnLZ5kyjot0rl4xkCg65LHrHhw2zaD6B1yg5RDU3LOZ70wIoFB5gx8kIVkZEp2TkDbxZdIgeweMzqQZnKuQnFYO7O9Yc75nf03ThbXdMZVY+yBttFskg8MTr8tlcRFRbhpKCpT27Pptb1uY3bh79S3EibTB6O1DnZoUuxm6auOOrYn6ROO7WLbmVOv/6UDOeimohilFOTDSfDqv3yAgLNk6F+04whooVON+YaxXkergLubIPJSJIw2gVk+q5TNnVFM/R4qmyI5Gh/v8sQHuoLIU70behVMvmSDv6NtCdrvhgBrYmZvSwTCjY09T+Eoe+9ZZ+jcjlSEcntTvkfA408HxOCfMqIOAgkhLPp0kqB6o4HO0rxPM52IWDcCqnvOTsWLBpcaVvyyb3j34UeGFD5QufC5/tv2xp5f7eH1QC5y+uLL3U/3NyuDK4YU3BXql4V928oHL+3ujLLzc9cP3iS/w/+cmMr1aWbFJ//CP/phMrk3O9PLDyLJyUMxdpyJmrST40/DBXiuZ6eYMTE+NoPsBxEuMash2Ol/K1+PbbL6n/P37q5r80XMVNzVWdjENwKg5NE3DwT8Ih8DE4AAbkeNBv2rnux3fpjx8/uy++c131Lv2JKTA31WD20SkgjhWGMskeYDDTwtB6jp3TS2GWfTWYHU3T5NipBFO7PDStqzc1Bephfmbxqqc+rG7c/NSHA1Pz7K4s8oXhD0c/GPjwqc0buZp+cy71UxhhlmCuHYZia9pNiTcAc3NUOaZZzFhIPLqXj5OXaSbzP0/5fi2/pP79MV8V1p+DlsS+T9NVu/QBfQ7pZjD8GObpEpinRtSTDNQLJNHcK7GKP1QSDQ0p1QjIj8lL5IB+iJU2j+7FekL8nc/AILxV/x1j/XfI+O/AMqEZ+2tF26CefIa0ASwd+uz679Rp8k9Ub8OKapjKCLpDMC68498fwqvO0v5uR+WWV5+5wEScDAu+df5nG+WNEb4p1/OyHJmSs6bjqQT+PPCSo+pNJHmX/vpN79xFkjfpm28iI7UDghmPwC78XoyLi3eJd9Hf48DQjcpg67JfiZEUXqT/iuy9iaTu0n91kwZH9M079F/xefyx1E79VzuwrobmUj5I9eo4t5JqbZGqFqf+7FCmnlFBGp1CZmb1BVyYVWmzi9E4k3lxkNVmXK5CMtCzf7LfgnjCBNV0jNehmo6iu55RyT7I2lli3NvnjYuzRL/yU69/Bkjw346fhw9+of4LbyjkJWl4H30Z5LhhjK5JroObwfXCKpPjyimU5j05DIyi5B7MaD20K0Mv7cowBPD39oDEtnrys1jEXc4pUZoTA2ANkmSGYL29E2YabOKkchIH8Sq0ktUTw/oPmmRTCGMC+AguKZfxfMw6lIqE/sPn9ijvR0OpIUuc5y8rYhZ4UYi53Yf+BTbv/qHBEXHzQoTZh0Vi8ZqeTs2QR+w+v23EnU6WTF4Lof0CDp89I/OPuKVvFm552da+rp/Z6Mf+JD5H64ay4/l9OdA2MPW11Eu5SckX0pjbN2woeHmHmObjUp+v0JcYxgSCVDLG4tSi9JrZJCgz05kLz/vyHW9/pmvJZy6/eet1p69xnutOzSuQmQs3bjqt3SeaJG9Ujn9laEi/e4Pv7u/mB288Z8fA4Cm57nB/+EX9xz/bfUrObPQ4CzfY18zdm5x91o0nZ71mQyiQuzISefnHOGcu42zifPHfuROBy4i2mHLUgqq2wEUVoCXwGlwA7DOrj6bcuL0qrIY+BmyYAKygy4QJ4iMW+viUT/Wlkqk0XwANJyw4RMmI2+Qyg3nhwpa5s2a2OSMO78q1sqHFZzE7BcHkCLT6++dvmjfHmXzs73xKapHTvXKNIWfvuGBJ2snbRBMhVlfQnZylSo7e2eRbc8Mzb+hWLInhofDc91Kr9haji7s83ohTNVmJaPQ2D827dN7TZM0lXac8bOCl6G2/ut/Ucv4lT6yxDTT1NrWpAZdoSS9fG0lfijXq3+OuF98Tc1yUm80t4uZxuDy1U/0Q00hPzGiDh0BfLC0GIhQGZfccizkQNLW35YdpfhdXMoMe+AInt6bzw3MXUaEPdDFmw4YWIIsxljakCmFDFiiTFlOs0CjfWzCqPrWASQlDQWPzwpVXbrlv5L4tV65c2GwMTj6wW5rXfdrJ19549eoNXSdaSSE0qz/co/2Plj7/1p4LL0ws83j59W2WtnUnn70ok1l09snr2jALdOK+5eyhM2d2tuVOH/iMgyxOLJgVWLIBy91PWbzuym3zLvSf3dqK0xRowQEtNM5HsxlO4L7GlZ11S3RuBrNAtb7gt4f+4z9+zSmdFs2Zdmi27xhKDvJXh2b/juZ07bM6bZ7OfS76HqDvQfreSt8T+F6Gs5E7I3fGjWCg9WuBfi3Yr7X2a4l+zdrPvWC12V2BYGsiXftH5ljgkMM54WA6rc0JEo7RGtOmcySOBC64kaw1As8mNO0DrigkYRB4HBBxjOAnDg0mvqi/8sXE6sevuDBl2f2LFxKb7qZEzajhWU4HaUv6ujOxGZ4M2diZmndT2h4MSolTz7tvnNzyXR+tuls574JrZjrb9Lf6drqfuJRRNLOueXVTcPSJe5zJbHK2fw5/w4x7++6e421rs/VuOud82hvhqyAc3eJToG+4MQc9Sd0aKQBZQksaVGhFbiL5+GVNCYMj0aSMbvfO9I5u/0/yInlRfwIDPvPnL4qIkagx8tGhIv/Po91FFGXYKaTeJ0KhcrcdZjUmjSI3d2S0BJWzPuyGU/bR7Eif39xZTvjq9amlTuB0XwKmeyiMNpk5DJu+BHXK53v7Cuh9oP6oMEFfQSohU59BhsQlI/ZYKMgGY7Loc5JN67etJ5ucPr+sP1gMes5840xPsKg/KPuJsd3b4yALyJrh9euH9Wf0v3f0eNu9dttf9b+e5sM2NCtWmF3KHN9pRPqrDVfjep63eVIHhgKsJmO5ptwabt1Y9D2PJWYsDwYzgMDQx8h7Yzb6p9xmvpCP9ovLQsouTJjcpYSKH/uPxp749+sXhpSjS+qp67Di/E1bzE8vGLaKz3IWzgW69AlUT/PTyKKHJt2YaGsJITtuoBFag+CDpd4q75Psblo/4QJLzYGDOESwzwN6SYHLwNSPkoLK9onAr/8LLnsPj+7VnyLCtTuf15/iH9957cN48C+VCr/+FfSgvowq27V37R+9/67r2IFGf5kbdElW/+sCYzI30cs0MTxG5HgsWc8UG31a/1kRs+gxGYzlzSM3D3Asx4qOfwK4uZs7myu34O+bwcSjJRpmzOFTspgD05FDs74TqJGmvtQkNsTAJhyCq+QmNDNYxXLHUga4XEAVFySPWy6FW4BcKibGsX5QihcECCjqw8ZULxYteB0GEOX1VkxgpxrlU1L5xEB7i2wFMxv2/anl533lO185b3nKb8TWTKSLX185cnnk9IDV6m2Ot3Wl/bLpSKVj9faLLl+Vy626/KLtq8lalsCLFX7Ye+i33DfFzwhvoNYkqOgoC/+OnE02/nb0H8ju36G77Hf8PKT1Qu518cciV6+LN5OF/Hx+7m/1h/U9Qmj0RX7e79AJx2rpZnFFwxbQ8U0wj9o41KlrThiJqtbogRElpqKzDQcuYbT6UQUVCl7oWJdfIZ2k60fkpl8efZN88ZfketzvrPAHSJP+B9qWCGvaNut/IE2ozgOMbhizJ2HMsgBtOYbjFchpXUB7l5ZkWcEYfBGryCYom0BFasXMRUxXbGbRC1CWSmozgNRNRyVZAN4BnQN9n+j5FBx8J6ErKh0h+hnH5RUvi8aSKbfB6QgINyYNTfKZOBn7fsCbwu6WUEdIPwhvWZpGo84YvT3SbRCe8rs9j8gKHD86W7T76OzNsvewVwlVOnxcQw0Y1m84GzPgRNTGNXuW4jJWjYgdV0g+V2P6qIJF0pVasethLFwVbmHFrFw939jwa/rbLhirsd920txBA/ttOYOM3GCf5UgUDIvxe0QJtlnSDzbc6agfy8rqUwsdDYSkgcd2UJkaZXWxtKsT9cxh/ybmlhPNVOMjOcYEOfjaK6+QDtLxyiv6IeRwlkRe41/4nwF7cgf8ZjOtKkJ71JKh7aDG08louCaKEieqjP8EfNIf1X/58ssNOWAaUJnVFSxmmeVakDqAQrQ0yUC5x1ul5VhNdd9dC7WCyi20kVoLNlLDyixzi1yb3pNTfpoIy9pVPRg0AmEYr8uko/72gZanDa1efo8nYXhav7vIEuzpkMEbOYX/nS/VrY62Uo8WXdd31/J0rSCtcmD11Hv7GKuakTWFSNMOPaWkEf2ePkpgAZh2NlHSoprvzYNZNkASciLu8TmAodHFn+JpL5ua4Iwlz8sGAqIjFvRViGgzV/hHR89IZniLzWkQ1nhD4kzhjyEFWRdbBWT9Wbv9CC8pvugpR3jBbnUajxx9tqK/a7OSZoWcpP9WWE29/M/Wco54bgnQ/nygfQpW2TxX7kS6Z6paIqOFcyhP1Ww5QXOpEzGshZuRwSpxrpTIAEZt3Sx+3zdACh6wCVJJGqxwgr4A5nPd98nHqA1nCKPJaYwtafLKW2Y7r13jNrq9Z3rhfc21ztlbZG9T0O1bPXrkL7NmuYPkCdvMhTOtMy4mZyqhZ8ii5du9EU9Q8SQ8NyzXv/UMYNwmmZvT7YpXav/XnqGhHiPypAJ60EPiQ6hj0dZS+JdCD3dBQid3SpVU5Y8r3uzevbv7zRV/2r//T/XtP+4jL9KPffT0Q12/WfHH/fv/uOI3XQ+xdblYq4GIcWlY82gsue0QxsmxKMXXBuzmrVcoEO8AwSgYWNcs2WUsx8XJg14izyY5RYoqQjyFAcvi0HWuI+nE+6GhlP7N5qFUtmmG4+x7vMVdRTCWXzpy6HPYhunDpcV+sr6ls9h10hZpV9dJbc2vfD+Y0O8gVx989bnfXK/fUWysA1tWg3MzV27G0UxQLy+Xw+J/WCklLHHG5haWsZg4DDOsmSKtv9DijHNZhS72BpAZlsm47C6b2rrQ7c3qc9vdWiesJGkU2x3Ue5STC3LvAEEuUD21STeWMpbhk4UWmHapaF6IS3GYXZ+EexHF2Oje68kIEEDfO5kAFHlyNZ2LsOYVDYp4CsX9BO4aDt2nrbQlSTvNyPYi2uUeWhffQ8s6506LezdLqO2mWbTdgyBRsCCuG5Dfb5ObvLOpIdjUCijHgQKy5u8veXuAMurgCdSrXJApEWCKJ2AStxBafhWtr2KEtkZQox66tNGk7WgHjzkvebB2UwZTpdjscJCLHFbZdonDegpJn7LpkpM37ZCanPpT0uOg9yduNjY5f+Ryu116gVhFsyCJIm+w3LdWf4Z27FrK2+WExfyW0bbZ4XU7rlk2skJ/xpd6pGkDWaO0hRVviBBeMAg2k8P+wpp3a3LsPPE5cS0X5mZyg0g7fz07FNbomVhPoc3KlmdSMTCzH2k3RJcPrD2gTQ9auljtATIOENrrwkYR2mC1NIyM04Llg7ZmsZ3SLtRKkyy0Flnj+kvCTKwUSXVR2vG9fWqUkQLLfQ1hvp65lBLisVQO5Xa0ICckLGqTHIYOgoplTj7vYiSU1XGJ3WV1kEskT/Qpk/6ks8l480UnW97AT5K4SH9y3T0WAzEAwcyileitwtsVft7IMnKNy6XYL7cZ3xLtKXn0A/vX2hSyptju1Z/ZQP7rvTXftDqtZgEDLES3IYXZXNuIeqrBAVYKxpoWceUCzrWZLLakHNIK2L+s3K4gedpnAXlycMCFuij270NfSzsGV9x9/f0lR4bmcoEAaSJhvh7zTiXymAKlyKmk0UmM2PSkMGwYxGqAPpxUPtUgS1GsF9tIQeft9kfaFP2ZFSPLrnEmHJt9p615wRdgkGeziNQG3Wzi1/M/1e83eloel8haRqJLN52i/+JkG7Ff6rOuvddtZzQSbIRU0IH2Q1eTcYf+OtgqlVrcgnAW4T2Dn/q9+rBjTo5l2hZoxVeOYU67Rbb3IWNQzLEDib1amomYo35gCQHmdjA+0RUAq4ixBZaN2UTAypIhkmAtITHu7ySCJ6rKBgc1QpN5eRBWk1TSSVB3J07fZnvSeQ1ZPrKCrPG2P2If/RD437L7PfLfG/SnvW3ZrCAZ/b5v3guIL27xXWonVsT24ktPvghnElkrPd7scOo7YMj113cYm50/9LndPlKxSi6TYHffy19eoT2CDFS2PsU5YJWZVdNPnFSy1vLJOOr0w6LektOGDli5n2bncazyu2Ty9I/VftfCBHwiKplBQTKctefX1z7SEB4jKdCWyL36pfoh/pRrf73nrD36u7WIp+eEl0iSdLxc10+fAphcsOLNrFlinioCY6jWsxcsLHWh5ME+S27M4ypbOLmfVaOjC0umEGEHSQpSAXQ1+AOIrmm8cQWsnLR+kEFDwWXQPKa//tIPXm6gD8IyPAZLPc/Fw6r+WP8MjE570HB1IIm8csmAGT4Wd8nONCTPRIgStD0FoUS6hoJUJ1KlUpkWpINolE2CaXkNpnHiAFisBLEBLHUCWO4aWB6aiwQEBNK5+8eHcRxEM208MQ2ItFSzMg2Mm9FspMq00ADnndyXudtqkIIBdVJGu4nBu5vCy2TrqQzehzDhi2Ojeqo8x+EweKLx1uFl66697fbPP4COAIv7BXusLTt0+oVbqeg9qUt2v+DLzhw+ccm6DXjBTfIcs4XznnrV7Zvv20WbcrnLV2+9djoUPUaf5PVJWXQHq2G+4DPCu+p1EJRKfAFmJPzHFsBG0AIxjNqXJrhd6CvAdWHSApo4nCkMC4VkAePjhbSQ6kvhlIcrU8aUA+Yp9oOV4EYOnP8FXxbevHDDND+Fsn81NRljxObzm7zrfcP9IVNasClxj5EYztvaEmkVHBmbY6FsHoqkXVmXSIztIm8KBFWPx2pyGNuajLY2h8MjignRYJH8PqPL1OJWzZb2+Gyb1dJSsFmN6dVOj9vZGRw2OYcd3tmC4CFCDxGEoGCRrW7JJRPj3PYp40o2xLY0mxcGrB7REjFlwqJ7qVdpahKNHouNvzzcOtxiJpLkshLeao2rfIa3mwRf0h0KhJrDLiMhJrMnYTYJixW10+Lo8AbMbo9gtqopJSK1C3bBILbGfTZBsLmNFiIYjcaU06pKsSsutyUki00W3T0pkZhszEfDw5p+K+fluEFSIED5PtWgFnwwJsQYyxAnvz664uy/u0sfvecj+99dt2P0aWen87K7O138uvN+0Hf6eXe+vf250xdmRp92uS7laM/Ds4FHn67lgjN/3CoOewv0VlHwG2jrvBlVXAuUKuqXM6u4FCaqNOaTP1Tq6R/vYVnOU4stjxYbdkLEOND/okKDYHMp2mBqoiF3vG2wPA/rNlYnXal8f9y4+9Z0m/qD6PzjDxTHezmgDYBVWqxGqxZGZR2SmS3NlThTzVjH5ckA+okkF4W3jy4RbtEfqYjLiljMrR8c6/dSty3QNk9wZ1OvDaFVrKEcagr+GFays4rPZEZzHtJitMugM4YEBNUEwKCNu+OsByEWg8VpMRh2HeSzWPrFlRwWmv5AXYJKY4fUsbIO6qmjrmjaCbZOO9I10F5pH0DfAhCO/qPGMBlpH2CEwhJOWnPOTbDlMRbqBQ2hno3nzmFkHSPpLMSK2QiE5h+hVxJ7oQgFDJxKN1XuqmCklX3wv6rtVTCMWsEXHBAi9OPog+wk/xa7hqv15twr7qV5Li1cOzcPJP8vav17YL0OZ7SlOS1Q1RZmsQy4n/Yg6M2W2yjN2k4wd9Zb7axoSAOAVb1WpB61dmJXjaSr1AHHhqvasKs0H7YWV/cVFs83dWo91NooVLXFYxkPK1EJxh4CFgdtoVEa7oBVpnsQ9J8CmA7Pm50eMTNAJXSY9eCyyawPzr6O7sFh3GxjyTdaXC5lBlA6+8l0HX18tQ538VgfdSHglgq2CE89ZWw/JbErkglWBQBbx2sCdElLOhJRfcvhFYn41JM6Wq4lZrbjsoOh05rIkZZIugXORUj5OM2Cbmfnf98VjaQj3470GLYTh8OHO5Z7fKHWXG61L4L34cix17gB8dvAOytBw8Ich1QVrTiQJn0ZbUkV+0JgrwaulMI8g9n9WkTeb3UGmzDTR1PcpWyOGhGwMJFcFhelvgLBGGsKo8YSAX6r9auXsJEkHK5dgs14wrDugKLZQvAbqF7GYxJ8pyk4I75l4eyZ0TntqTaZ3Bn3O5tO9ZrT82L6NmkBucbrUZuSTlfr6K97FxdONRucM1qTfi85vXdoU19APWuLSTrt6Ki0gDfMmym7zl+5YM2mU9sW6Rw59A8r+uc0u3o6OrvwV8/JrJP5WEy/SppHPutzqa0p/MW5s+PDc1pbFfy9Ql6Ud59z3ml/PcZJg+TYvP1nrLutNVrww48xP85Krk/8nrieawaNfB6Hjqg09d9IWaqXg/LASkg6mfKAaniIlYdrnfI+QXKyTByhF44ZmFcHyEL9UFihgH0U03wqLeKCDFatCgbuME/74TsptYwrX7l55JwL7trxUnzdvEUvny27Oq9YOHdWfk0i/NTQ8BzfGRtXX26bM2/47FmLZ225Ird44FzBdfPLN9308s3pUy9etPAfb1bVWTctPGFW/qyhVcmmtScM+0697PTLbMML1zcv2rjmqWdXncvw7D/2gXi1+A+cH2wPzuMFUGCsCW1+n5KwEz6Mt2TEVpGFFAEZ41Oxu3wvTR2Ace+fu3PuGWfNIU1z5+60SRce1K/777Pc6VBh7sG5Oz0XHiS34m5LKF5g1+l/mEs2ngnbc+Eb34avGPAr/3OWu3tmYS4Rz5i7U6ZfOtudzofiF3WegZfqf5jDZHul1i8QO6aEMP+dRlgD1LJ2U9vByLq8wOjAvptVX9COGVTcZGi7lyY3KJ5Gg489eqEgs1SOumVciMpRd60avzJ4/kNPfrk4i4VUimisfn9o7dDQ2qLwLSWbDofTWeXoIpDaf+EPHP0Vnhia0D/dP54NE8hgYzEU1QTjRqlkb6EvqxKfV0LlgYCcJpmf/gK0W2vc6XR0OEgT/WjV/3jwZ2Tbzw4StRV2nU79LSd+xPX/1A/+4qecQFKcG+zv34AOMcCdwN3DaZ0ZrY3WNQ5my50iSuHODpDC/XQBdFXLrn485pJrLhvbIVzvQM8gtGUlSOGy6MLCRjQ63aFBuuVCxwM6voJYZx9gTY1mYFYRj6GPTthI9Wv98jc4WyAxc/gEFjXTPP3o/waFUwZGz/eC9onZgaIaB4Egq1h1b8QcQSxy93jDAvCW7CAe2uCVpD5vWLekKT13RSa6fsfKYnLB6sFO4WFT35I5scFVhbby7uKXTmkL7HXJHd5mSRxa/Kcn168mpeXnOslKyRHI9K8vnH77PGnFStHTNfvCuScutetVh+TpGjxv+PNPWpevkNe1beLDoS6/YpTAnnebBkY73bfOWRRg8d/zhS+Kz3Ancjs5lJWZKqomcRo5jNJO1NZq2UMf/OFxIB0X05DQMO01354t+2mXQz92LJao30viWPW4k3krMCvEjw1u+aFFJyKtnPLz1tZEpm8m7jjcWg9QNdMHi1p2GBYpTi71sIat+RzSCuhI5Ui8lz45QzIq3rARUy59sC0Nk1wfzmEVe58laTZMatiA+SbFx/1ei1nIdG98/KYfPjh/VWviZG+7wWg3eU0q/8HLJkVpnxU/R4l8IbZsMNu+MtWh/iKbWqv6C0bFIttk8wxbK7++2FMIDqw9s219+erepc0hpavf2qRE3AlHm1jM7ggN9FkdJBa+L6AKc0UxaLPeIzqMdqtsKdy9iMobsLLFZ2v6TEu956eD8qG1igQqWcHa10xjjUTjspnHd57GTirk3tonjf7RUgoaBjm6TbgFo3p8TUYY6XMTsOPF47UeMMYcCGq2aaIJld5qiROBve00P55658ohGhUNqdjyDPsq4YjytEEGy6fDhwtgSp1dhS9aao95sdBKwlITtiB3gdoayGb3uV2KiXoPPCibsLtGPQ1PM8mwInAlr4nWQGp2WZNxcJlZHqV9pjHAwxofCTJrglQANZJ/pYKxo5Eirbo5t3guOryLBFv0ICFoo1c8y1oaHcaGRJXKBJo4aH1hjNvD8gRLkgU7DVG/JOBqovEykJwu6uhtpiLVN5UAEiDjVABZ4GUZCeBw0bhXKMKI4gHi7AtarCam5WWw0VYjASRGgFgLVhmIBqwyKDW74JwfPTywhI5To4a9MJkqDdRAGhTHSHLuODUYBfgD41Q5ug1LcSgPLqvxiBu4ZFO9Z2mm5u4BQlCmKNsdtG0hFZZqRpMxW3CfxyWb6ONcJPp4JA/NH8QOTFaKPX3WDXa92c/xgpF2h3BglatBpHO45tqgiAkY4JDR2qpxN/IyjBkb0zqDg5YOiAhvg6GDD4eocB+Hg0ShdyMmZTftqe3Gth5YJEYfxaNZ0Ye1z0NHx07xlCgOFoaDTFmY4uCZiINvMg4JCj1j0FQjDrTtcPHcRhyKFHj8o1yJSyTly5ptYwHORCxWczUErPXaEFdtqlLYnYfKktWDSxIwKbaZpJ1sfRYzvoMkZnBbTShaBSOrXqkTnPYBq79ySl2c0Dow2s4WkxYbiE5bdY+9/nfwWgFeJ4XXgY9CKlvommFxI7wW3yfAm1OEBpjH4K0wIGsNeI8P7liPR1Zv3jFes9s8tSRaHSuE5qYWYk+uG8NCxkfef+9RLF6ssFJGVrHI6hfZiXdOqJc5DrTXY2l1WGLo0ZwETXwqNCgyVBALtMSSKzV7cDM2Xan4ZAg93eT9RxAWrLB89L0JQFbIcn0fQvroe6z+shFS3XbkyHjs738Nb2wc3ujfAq/ahGW8YxBNgLd45AiD9v1HJkNbBESW//9O26iAsNbHeSKs5PARxgSICPDI7AbSbgZYKU8avLSuMMgNcmPLMXX9YMWAm3U3tqEzGZNZQJRK1ISqZ21osqwJLLceEyE8+THg8nWo2ePdKnW4yAjCg3BV9Ef0R/BRYBMKcKnO/hpHhEPiV4CCGI+O0FbvXlYh4g3SmhdUSIAUYLu18GgipZJStM9d6MuAEgZqFicZX7P4SHq3wWA2m+12Pug0m/wwP7/M8yaT2WUWX9T/c5nMSx59iVexmoiL3wJU50XynE22mJyGV/V/Xu+pz1tKIz9AM5srCzUambDuGkuKgjR3A0Sgd2waW9nkLQWFWvah5pK1ZtZVFIavkI9isSP1UGFmJ20QQemHY5nJs3pjcthROeOMx97BVYgKGCCc81uMVt8SJZ5/h8YCGBUb8v5DXCt3cg1OJ11AgwBYosEOszLPTRLVOzC/nvcHwi2RVtR2QReIYzQAK1ZM5nAsTo8GZepdGyukTkk1Lxsr6i2kMCcxQSsDajNnxbX1qumHtiwpPvYO+TPZeD85fL/+JBv+cxZf98U6M1674p3HzGTt/brtfv3hKfUrp9ZrbproQzg8jVUsrPIG20aA1RkY80jVH3T2gmi2OJxuD6tWVJvgCDFKNrtL5o5bh8PXmkccrxJHvWLPFVfsOX4hjhtPX9Egs9D36QI9L13r2S/XujTQhzgqtFDPBLoBjSe60WHsq/kQ6/PezNPW/bCiO6yi3+o66icvkpcwWxE7YWLjWKdFf0+IYKdhZJPRLVlumvt3Trr/33ZzliZonnD3LixE1+eRM8fvzh+gUanDH7014d43wL2xp2Ydd7YaG1jTSdDebFm8vUxvL+PtlSm4g+k54eY9/Mlf1hfu4m9tuPl39Z/yJ+/WFz4wOis79nwuxBt9tP4xzJUqxsUMrM+4j2Luo7f24a2DkzFXCykhKmP1aCMAGw9u3MwfOHL/wfvJTxqo/6/nvLrx6G/4v/8POKHbsw3PCRuHI30cODzZvwEUjyqpBVUWxkHZdvCcVwW83/+c20CL4sGNB8k7AN8XYVBwOPBZgcdov0EDZ8I6DpHaeGZa2WSsYkc5VjSPNT1moooP6gn9hyv5PaNnk4cF10c/IC79arKnKjw5OrOuxxQpXlhpuZzDVcIIg2ikg4jP03Bky0aZPixChD1Ttv5sP5A9Rip+nNQNREvlnEbZXTb7VOb9YeIEnzGg0opw1GVjSSR/SDkC3F4Je3eNzt+FuWDF4i7hbW+YCsCjz2IBvr45JFxQobw3TPvreWi+3RwO9UCA0EkhdILxUDY6J4AXri/IRtqBmCsZQfyVrSpr4NIAlAKSj4KUKGD5kzAOmP7u1u36bQjZguu2ko3X6YnfNEL4uv7e1hsAwBKcPPs6vVV4slKfJ0aDg8KqcnH6HMTWBmASDZ0TGFWkFBmjiaeh7LEGxgVP6of0F2oEKj755A31/+Og6B/SiyixPnqVnrzx6/g+oe+om9LuYg59AUA7B6WdA00XowtV6yCWG5dEU3aMfE6gMDcetKGLo9OFvIyuWVuWOvuC2ILEg6XjDlgYkcDskGUinfFhm5TMTPkWaNY6o/Nm3UbRY5HnSgONwV4ArJ6igoi2Ba5UuGlwOm0anKbDZgL8jcBrIVmzAwpY9FG22gKYbAAL5GQUagPFwvtmMo5CBah/KcWBBvj1g404XFqhY1PDAp+UWsehQnPfzJRTJtcGME0QzBLWn+2jVaJW609HRo7Q3OBkkXalGHXTH8Q40vnwe8/WbCfW8fomjEqUfMEcti8pqc30QZAlqzOHj4Is2Vw16kj19rhW6j5Db4OPrsCUSFYLWk8GZqRiUsE+UXC6avEet1eRWUdGVtIJ6kaJeIF+JuadxHRa+KPuBfqiOhHuDmBWP9Mjae/nkVozaLoJhtgr/Ldp9A7zbg+9QmN5Yz3qme83g3ktXir7ZtQeUYnOE9WKy9I+s0s1YV9njMuYqWZusVLnYA8Tj3LtqcrsTRrrV5HwYjXOeG949pTXYjZb+08bgtBGgFYL3W4N6u8GEvwB2vYaa1zq75t/pJ9Ae1z8YzGUj/qNBv1K2m9vdYtH/qxrQUu9FoblQOYwI4ZGHm05LVct81YH2rVtmbK/OYHV5Cl8BgJm7LJnaLblsMA9QhsWR/MIOX1uj4L9ZYU8TegD9qFBUlx2cDssoPbuJEDhpQFyOLCUjNBE3WwgoG9eGtBtgaX65vqRmbYkuVPfkrTNnEkMZsUhbPUFCD8TDutbyJ1jh49+Dg/X4pjMRvJzzVwE7OE0l+XK/pqW4EN9uuympTxuL7p7MhnW2MjtoiwVaKYanDzFGirkEtiLecxWj6pKAtBJRUk+obAsctBMD6JxNFK5EPSYdUX9jmK9eAErLFMX0mOoTLGrmeEyOr9yjn6oOGbWj1TOOadSHF346K2Pwri4OJf4VfFhLspx7rCghoXcbNKHFZ1AwGQqmSoME8wSdhIXaRm+9/wLfv7AdS0tj7qMnu94el1X371t+3lbZKPj845u9yPC7zvvuPvg+RfcOxQlj8gZx+ccorzlgm3b79oi93hf8hjlRxpy93F9y9T6J+EzWjM0R++ETGkufXJqE9qRGZhgbfK+ZHt2DiUapiEUSL53WMgi8yq1+ieageD1zSbDZIj0RVTFi92fQdtPi/GYQ3QSxUEu4X3J1ZtXJ32EkEscSthLm0J6f+gN7STDO+mGMVjc9vr20x//bHF2l9mcPejNOUgmK9ojAcXb1GyxZPWfO3JebHfHP6UExKgYU+71++9VYrAZUCqmwAk97Uq0rS1qtYzNX8z5DYzF2snEzrxRJRFNYc9WhXWnpy9ZpU/lOCZ843r6mA3WTb6y6wh9+jT+0zcXa76F+j3MtGNNay2a7s1RaWdpzO5iCwF7MshYY796C5vc2FYR0wpoBRD9KNZ2mNldT9fgDzCuouYlPieq1jMPeyVgVdiJNb+Ba8zm6WrwG8jMb4DP5pNdtLd/JN7WwboN0P1gJNnWzoo4J7XJw5CaB52EOdat35BDxyGoE9hfXtvGH8B6ytH52zTaGYkyPPaaArrVnmBGDuMVug3esRpjLxNi1MtdZI67/5dwCnw6nOiSwdiAfDxOtQcIHBejCnXs0acSjGEkTsCnCbS1+VOwaZ2KTaKGzT6v0hwaw2WfN9gc+5jRAQaG0SG1z+OOCnWiVJjpNREDCjmFn4qKCbD7YC5NhT04FfamcdhV/zjsiq/Wx2Ja2A2yp5tMC3FNyk4EVX9kFx7etWsqz6iUa04dh9RL4z/xLLZgTNBH+NRgb2uA3TuW3Y+1V9EqtiVvJfXnMdQwY8/3mRZ++mRpjDd3EhGXdVDipsEGabyjva8/uYN4+tp37EhOMy0w3nHyjrVrd5yMLbEmz4c4rWedPAodU0ehs2GOR1tTE+ZDLNn2t87xOI3hxD9uht9TxChB5WNnOPq5OeMEXFhVU4pbNgWbtqnYtNewecGrBJvDLbHEGD4veP3BpnCkNfnxGMWxllX9BHyK5+HEPg4yIzTXewwZ1Icn4BOiuWqd3O5xfMKZUqwdtKoWyn7UXEBuTFImTGWnk2ZhLBbI1hiQlQHuC6jNJlr3FcTniCE/xsb6uWPCVXtVa3fRBKwMRvnHBSJXamqhXk/NizUZ05NHhbGuxeOARFEascCQ0LQkOrd47j/ROVmZIv8qdKxxgaRCkoaKJveVCWEdBfPLhagHNEBDkzU6hCc9shExHvPOUVPKC/xrcXgE+iA/TZafNztFt9pEmSEYwooKu4vz1h6XpvRrPvc+o00mx2+fky9Eqe0QPZ7jLjSu5B3/yY10QWC+G1HcW8M1AjrBnjq20QxoBpik2JRpEECJSQhH4Hy2HKHlOJEwWJjs0fZaIIuVJ2oWn1kqjzthI16aPkcdldiEy4cPjd1ndrpFSpBYtEaQcO0Zyaq/Ba1OpYEojRlzY0QBnqAKET6TB1fH45AmgPMbdaLi8UnzZTRY2D+sxf3g2EPiS+IJXBDmyuU0m41qSZoDM1JMrIo71mBm4QRgFbESc/5gIaOIz1Hx+fEx0aWWZlBVPVHYsuLTClwRjIPgQ0z3cdYQxdshl10+5pIRqGAGycZqjGISzbxQvKqDEBapdly+8g0ycuPWJ5/cmu7qev7SL73Gzz2FzKIWN3l/1RXIB09fu/UZx8arf/lgwObYpN9fe9bjOG7o7w+z6EMY88tYY+IwwCwHDcxhRQExE0zBmggGS5IAKEzkq+S+M6+ZCAZzXlA4vqpfEnyoeM1UQHDNILW83EvAvuCAwSVQdKMkR7ApKMmhYUbOBLNM/+BJ/A9fws/K7u7u3dR7sFzfV69nvQZ+pyDuhjWH83h9KgCJSSky/KBca+JEcUjVMPApmPN2TX9GvHDJzC68S7pvyYXm7MB1G4L3nXnVo7zDvORC/kB+veLyLbkwrP+ku5tkwxcu8bdEzh869WbjhssfvUp0CfyF3P8DkKeJqAB42mNgZGBgYGRw1FsVMSWe3+YrgzzLBqAIw7lYoVoY/d/q/xzWu6wSQC4HAxNIFABKQAvLeNpjYGRgYJX43wImrf5dZr3LABRBAfMBiTsGS3jaY9zBoMGygYEBCafA2Ew9DAysEgiacRMQuzEwMNyE4sVAPguQ9oDQIDmo/hMsG/5/gpjz/zPjF7jZfEAsDlHzfwcEo9gNw7JAnAVVK47QwyAFpRmhNAvQjDlQPYwQPpjNgqYPxV9YMEgvE8LtcHFTJP9sBdKK2PX/nw01AyY2BcovxaIeZn4HlH0C1U5GHaidO4FsASDNjAPD/MmC5G8QPgPEGUh8JWg4wPj5QPcehuL5WMIFFDePgLQbkLYC0kKIMGLUQ/OzFxCLIunlgIonQv3PChVnRcIMLEcg9jCAwf8bDP4MlgwngOlHHSjGhAIR4AaYZEESEWdABSlgEwUgrP9zUCFI5/9P/z8B5SoBYR2ue3jaY2Bg0ILCNIYl+CCjAaMHYw3jIsZjjOcY/zGZMc1gOsP0jlmH2Yf5C0sRawobH5sSmwvbI3Yf9g3sLzimcBpwJnBO4eLicuHq4HrHHcY9ifsFjwPPJl453greNXw2fEl8PXz3+G8J+Al0CVwT5BNUE5wiJCKUIHRDWES4R4RLJEFkh6iK6ASxBLEb4l7iLeLPJMwkGiT2SGpJTpP8JeUhVSW1ReqK1CNpIWk9aR/pFukt0vekP8nwyETILJJ5I2sgu0+OR65D7pW8i/w8+X3yDxRYFDQUXBRyFPoUPihmKB5SclA6plyjvEZFSGWCyhNVIdU21VmqG1TfqEWotantUXumzqOeoX5Kw0AjRmODpp7mGa00rSfacdortN/pWOj06G7TvacXp9el90nfyEDAYJ2hkmGF4RkjJqM1xlHGXSYiJnNM/pkmmO4wEzALM1tnzmIeZb7M/I2Fg8USSw5LD8s2yyNWHFY+ViVWR6ylrJOsz9jo2YTZnLI1sp1m+8/OzG6V3R17OfsO+w8Ofg6LHAUcyxzvORU4PXMuc37iouXi59IDAEV6iBwAAAEAAADbAJsAEQAAAAAAAgABAAIAFgAAAQABAQAAAAB42q2SzU7CQBSFTwsaiUaNJKy7cOHGhn9BVsaF+E8kii4FoVQKbSxSSXwKn8GNGxcufQJ9D5/ChfHMMCJBFsbYZu58c+feM3duC2ABz9AgniiWaEPQwhHOl1wNWMMKbhXrmMe94hD28KQ4jBw+FE/hRssqnkZWe1Q8g5j2pjhCflc8i2V9UfEcOa04Sj5V/IKY/lXDK+L6XRAEpuX0vaZdczu+WXPb2IQLD31cwYaFJrow8MCRRBwJpEhV7hrYwTk6nHcZ3yOL+BZMejbg8DVGFHy5qnOuc+7RXjByizc/QwlFbPPUQxygzLgitRw0OGzqW8w5YryFa3rEKQlmxmUtBRzz9ArzChO1fiqtjmn9tgJjLO9E3sPnvit7MFpTSWoMVt/eJiO7qMn43jDDxBptAW2qtqgpYhr0ipOr7LiJjBw59j2J/B9vOflLTfYG8jWZ7fAre6zbVlX79Apq/1tMhVVWWbnwdoc92Vc9LXPXk96stBmsc6RpU+za8H/8BJBMiJoAeNpt1VXXlGUARuHZgGCB3d2tc7/z1tgo89nd3QKKgCgqdnd3d3dhd3fHgT/Cn6CfzObMObnXzHrnep6DPWs6YzoLXv/M7xSd/3v91ekwhrGdsZ2JnUmMYxHGM4FFWYzFWYIlmcgklmJplmHZzt8sx/KswIqsxMqswqqsxuqswZqsxdqsw7qsx/pswIZsxMZswqZsxuZswZZsRZdQ0KOkoqahpc/WbMO2bMf27MCOTGYndmYKA0bYhV3Zjd3Zgz3Zi73Zh33Zj/05gAM5iIM5hEM5jMM5giM5iqM5hmM5juM5gRM5iZOZyjSmcwqnMoPTmMksZnM6cziDM5nLWZzNOczjXM7jfC7gQi7iYi7hUi7jcq7gSq7iaq7hWq7jem7gRm7iZm7hVm7jdu7gTu7ibu7hXu7jfh7gQR7iYR7hUR7jcZ7gSZ7iaZ7hWZ7jeV7gRV7iZV7hVV7jdebzBm/yFm/zDu/yHu/zAR/yER/zCZ/yGZ/zBV/yFV/zDd/yHd/zAz/yEz/zC7/yG7/zB3+Onzpj3uxpmTB35vRutztluJO7/20x+oEbt3B7bulWbu02buv23cnDLUaGW42MG8ydM2vBm9pDGh9uugseGniJgZcYeImBlxh4+MDDBx4+8PCBhw+60YlOdKKT0tWLXvSiF71Cr9Ar9Aq9Qq/QK/QKvUKv0Ovp9fR6ej29nl5Pr6fX0+vp9fRKvVKv1Cv1Sr1Sr9Qr9Uq9Uq/Sq/QqvUqv0qv0Kr1Kr9Kr9Gq9WqfWqXVqnVqn1ql1ap1Gp/FejV6j1+g1eo1eo9foNXqtXqvX6rV6rV6r1+q1eq1eq9fX6+v19fp6fb2+Xl+vP/Ri97H72H2GP77RrdzaXfi91h3eI/Yf+4/9x/5j/7H/2H/sP/Yf+4/9x/5j/7H/2H/sP/Yf+4/9x/5j/7H/2H/sP/Yf+4/9x/5j/7H/2H/sP/Yf+4/9x/5j/7H72H3sPnYfu4/dx+5j97H72H3sPnYfu0+tZ/+x/9h/7D/2H/uP/cf+Y/+x/9h/7D/2H/uP/cf+Y/+x/9h/7D/2H/uP/cf+Y/+x/9h/7D/2H/uP/cf+Y/+x/yzsvq/THzqj/x7/AibTMyUAALgB/4WwAY0AS7AIUFixAQGOWbFGBitYIbAQWUuwFFJYIbCAWR2wBitcWFmwFCsAAAABUjdh/QAA) format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}.glyphicon:empty{width:1em;} .glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}SABnzbd-2.3.2/interfaces/Glitter/templates/static/bootstrap/fonts/glyphicons-halflings-regular.eot0000644000000000000000000004750213217004753031625 0ustar 00000000000000BOMLPX.(GLYPHICONS HalflingsRegularxVersion 1.001;PS 001.001;hotconv 1.0.70;makeotf.lib2.5.583298GLYPHICONS Halflings RegularBSGPv5O5U-R`WhKqJx"U:r,/4\ liʚELFMƀV(gW6V`m_fZ}~Hi%[Dd"wz, ߘbAi*+2 8,媳BIPfI͡Iއ+ͱw3-鵫bb ˋ\.f0g-}P1'=n}@@ر rU +(,Ugc1wL9n`Gv!(\SJTs3d&ruN]}Lq45Weo@7@`m`ʆ6P p\qf3h<@AU&Q*]X%i,g!RBa/22!y3tM E zE2Ѡ˜p¨E`2);BhP*Ю}.]jE+I*(L=sVsXN:eOo[P6R6t/lgx(y{aD"Z 1(dWNrG|MEXqە:Ä"59Q)3eB`\YG>X)I '_\jЋX+ozTy7*au(B @ha@8H{/.ُ ʾ0fe3x1Q'pk^,[QӀalf@.]JYo4 _]ă98B xb95"uH0S? q+ T'(a;:<mHLdeM̤ўo2SQF2c(:Bl:(=bYDoV9hd, яijmTeX2W^qj>!*acz8Y"'r=φS*!\!v4IQaʇmiR3N%Jx">722M~ʽ2fG%!)qA 8( bv^*[p\ 6t wCsҐ, lf CӹiScD'3M%fa K(q*MB$H\gp˛2ԂXAX8p(өjĩoBfC #L%cftnpe{\듇7 ,XıP%"7X^P5,M vɓuU:AI1\r8iExX;dS4fIüIORH4 (FFrxb7UЈ@)y~c8  8=o-+n3D2 5Lf!7Yd>Ny }6+9Tk)$EԍJdZٟbYQt90l?,G )yaGA;;EtG5v!rϨ&HAtHQI6_[՛ąO͂Dk3QX,)+lUb'v/4/h8PnAH) Oc[ ;$0f󨡭YnK0s~kR_gAc 1xG )`BY|\P80f
i?6!<Vrv2yĭ(c Ծhp--0RUBoFI)OŦij2jD!Y|` j," ec)1d:n*F]|r=q l&#nv[gLiZ,IPv*]/ &_A.P@m5*WfS]*`g5˺r3̝݁]Bo hr/ODXk!K 9e%#{7Ap Fpt;3̔=$)@Paw&ql=աrJʆB]n u&ǸJA{)mPFl/0,&wpӄJܵcHKm ^rdpJa a&[zA†'~(/'[hvoX`e@0&fkpddhF eT]%Q*%RBYXz'R2s\8f=hszGqntU"=f]B`|xZŴ,('{$$LYSŔom" P:P#/JDÊd-,:N"Aۜ{m"ej J݂%C(v3Mx:yAI35/!o_ȕ~gŅu{}Y&IrwH٥ Ѳڞ"@ڳv4aF, !WEe$w2hD$!…BK)V" zuзL^{<7+7EF! Uv!!4=־.}$bボ&c8,<ܣ @Ù7t}Җ!G8sa} d^IGt&(")\<c8%vv fPn./ !×d@ Fh0kYt#_KgS:0s(__34 X* |B4v}aD*WwwK)p6zB 5|R)SPڭԃ&>;$\0$d2'ЍZ ]d};et_d^$kz, +ɭȄc8Ѕ0!ODPd-l8 @M%хx\)WYl(|V lNNoB@S:~eɎ B.abېdmuYH'#'vc=lN$BU>cjM)RRP ,!?*go$3@d6<2?ѭ/ϪX%,NPJo< smt(3 X@Y3/3d8]Iډ79Y`L$ZVԃB:kb[5@PZ!e"-6F.$[+}YAB`2|e5z52,"b[/J.+WՠQ(4F 132њTc0ńEM: GnBۤe65Y-`0ρ$N HXPZajL` ^DXJ !d HX9E}\ư/4 " {w 1)PBV"?={jQTB""֍\k Iqyp$A;$~L\ʔwdU@ym};uf"A )>'Ё+!œd-i1!ghg\g"[ ̳]b1B#AĆ$]vxh\mȴϑ"i(0/ś4\P3;r673<F=G2S͕|++@~Jx"9Hkxcs1ܘ"Cy2oK`8fA-DGcOa\EX ;ԁl2?Ȁ:}Ij,,1ɑE2 USW)C0ළ( v>0Ǻnp[LP3@4]{T~A?񁁀X4gY) 3<2^.+[Ja LcE;DUI`$H#`2r-@*EEŰOc U/㪽%]ϤBVeݖF(n!gN/<9B< uT Ո>W/d(ᨦ:9RN+h| $#g@q!(=~5$?xԚ[!em18% ,E!l[/)^ʥY qN)槪ߎO~Np?ai =0($S!wf`-l.j98Lwi;"͑\\+?_lQ"ZݭNqU. YTX3LH'N'c7ሡPq8s_NCR.1! sX$M,|8<@ >}ENtlX{t Fʊ1!7j4E"^ˍ p.̖ ꘩3@h[0zdT"qmh &ΠKlJLO7l Q!%t eV=C@R$M%G*1@^PQRZL-,1# eAmE4r͘}cJ$QS*RSx! ͞aX7;@"oYka1O+~4JQ~ה\Vp&B! w='l=Ď.D-͇$KlYD U4M5 gDGh<<'<_`r <`PgmXP`ѧw ^`#z-\#>J- B/W3]@Lo u /^ra@-TAYZ*,Hf1ZDFZL!<<R :.JU-J-dn8%3j x0¸T䡋hA 6񖐈"jI{u#yVY,ҺCdY|N:B(XNP|E3wQi6Ҹ a3N*nt^s k+Hh v20d &j B8NLŴ^8*'h]:s旇Ǫ$5q_.k~aDEs}#/iǤn&"587di2 TqYPLF=4Y"?F[Y^9 ZNJ7gHiji!ɕ-Z'2pPp,`:TO M6T_&tΒ *o7;Gm*g?4d tPIF&(wWv[(O$K@F-{ dCnA%$[A7,LdG:2g4̵3̕x T^ZFKp K+XϸkT@Dv12=G4haYpJJsC'fHcوM-PH)ot/5o!@=8pc 7cBTh|q$ _qP1Fq&2OV4h: bKn Kk9:]`=hCr@ys8r-dzde\J授| S: %&Ҕ`"όbȯy% Z"xō6)U` dK,Pi1%Y8)djCi#Y rdDY|)ʡP[߻Pqj;,EVcL!4o>ZFέWy~#hO1h|m>6& g&Ki_q$mrǫ9gVFi5).`)s&˴ m%!0<:I씜KJfMTMjN_CLG!cM*51n~0qw!sdλ?;Lje^ԇ-04GBTN^*L)x]#t:BKk 4BW>$R߸S2E*Ƽ>:\|PU X{;| fk ddQ$ʲ>tfΑ6,N\tDnEƤ,nf E&iqiy4ɡJ? 'ͧF#/hG C'8JfnfaS#Ӏo0QDAg/ťy.d Cp&Qx'މQ?YVGW!t&H cTZuh7gC`^(_ ǎ،Gu lPV@@zJPe/"We8J-s H7a[:|Rǁp ac U'?81>y .OvJ&mpZxmQR`xGL΄xF ~Ư٤ng4qV[4\lmǜ#Skg@Nr⎶NQSh8ێKg)^F^AԱUKxTv#I>lc߻f8ExҖ+-s! Bsec.SƏ8/V*1o)vp--Ӿ]JQ 947ŎKƾEz= l=k}j&9S9APIWYjnaL= D -c1c@a] Qg`}Iq(AL'4LJL%>;Uwn&Ґ9J[θiCjE7Ok.ZQkE/]ׯ%\2])Didx}6<= V?yMFp8X*>C;UV!Uo|%Px2Ű$`UlBjީ \xq 촙( Fl Ik݊!&jhS> K?!δH X{/uv8D&}@'^A8϶`Zs9-:muRD+FhZZR kGנI}x6GK:^{C0bP"#4DyZ!^9jYN%aSw;T)k$ hqHO>/҅FP+:` K^uJ>xx)GSO݃K,xU9QFSx%JO<8Nj7f^Қ͊_S qqBGS'ALط 1#p*D߻<`FoÁUMg5 WpE ėTxyiYm,%hTM6Q U 5& .KdQp&=/34vn;r*CD \Yl q4 p'z܈G}[c,^{ڌA_5xZ0y$mnPX7Fj/M mqP![$f6Zq[]ϗY1>ؠj˕>Z4_aƼ`[EyO{-m =J;anBF$ˀtXnta>D.5MqC q[%v*Ȋ#G`cq,sl|z[|אBrӦrϠF_c[$ BCJ -ΝH jG)RDYDŽCmP%~_zB["?vh`:AQx

e*:7G9܍M:{gzySspL92X_ۍ )>a^y"2ŻK^Uo}SKޥ*tvL~#:b-hvN y?D)'J8}$5jFbay)qگ GqTclHo_ T=nn:J[ :` #5aĩp I-Iw#^im|@Z DD+ 3mG@qo³N#+2s 8XA%aǃ8YbnZx{/M=D&BtL#iYN, `~u#UtD?؄vg0EG3dHp,,Tpm׀&3Ư9InVRiYiaxɧ;)b>7tVN0y#)6[kIVrT93>0Lurp"Mx>mceT㓸X{AdAZ?'Rl% L2-4CM8,6cP>BǶ$_7oFN2],:(^ O@^圾 B4zJ3Qv 0/^+9aG\D G0<s28u e@eHI=AIf4<ӢGMJ.=-xQ`5ĻȄb{lg?h[*>2i2D٠cKpi ̀iF=/>+7>]=x -^ yM+ɐ[ؘ :؞f3&I Xs8hK<{Z}nlyMCCܴ:ܚJ{b &KNlº& _dwOH?u'qRNkv_ D\wѾmβ =bSF4?,N{Ti3IĖm]|-;멟IqOX~4N+)G(Ӊ2"tAM P 財lR!h-Z1V;EP8;`88s׵4Qr!cBՆY*+2Y<[/LZ\ ~6m4q$dұ&N}F; e)8ڰG8.۝\[~e:j#][`<$$e'#e C(.$O6 ¹p\F,.L1KŠ(vIm*|@YI 6̜p@mCp:Q%ȯ衧rHhvQP"ي`{\vRU 2 R0#ѓ$p _4IhHt(w9z;!L{yYǚ`t=(hl-\[ )eC슉E24bxxKFI̓ R>(DN.Qmǔ [K1(r\EMZ3xㆤh!4mI]V}b^jƤZH%:4NȤ_󓜩bDžquS,RZ G#d }>R)(_iPyJg1/E-LI01/ltPʑJ5tT)MU*f,=MɀCmCd ;&Gg^\Db=u1xpF;38(A}(`8`' VmmBN`]["nL`1npK ctEz9E*ȴw 띞A2j-b5RLV#e m1A[g9EM8 ͘Ac6F9=fSaԓ@64LeMj] xN^qzhQ#l/p-H؜m d-%6E F#SK.t͹q :%=ŐFtjl:[K2rF oZikEݼρƊP?"#k $m . W FszQ$9 hcS` .}IV)59>ƜS~"CR]-!&E}7 *ࠓAoKE G֭d&ڒ}e48<0?xi!&/nhi/pG@]q[ФJ-BudggȯTy-^%?v2t1BAȰke*M|CnGTk5{Al4@"JHXJ1yRv6) ̾byƴ5. IkUh;!m09jgrMWaz&P+_WE@(xٱ`AH*jn Lb0i[Pj DzZR" 'Lw~I H3P46BKB TbtJ,`ș>9W94VNVl1JC3ҤXh+TRfIlvZ%̎)- /á;rÝz󵞖-A*iL9VHWxSHXe%&, ltS)XTM̀)l% h]ZPWqcExrhuP4rã#ZI)\my !߯/'yɬiLH1D)xWW^Qͭg6%sNszm,YEe2͗V @ʔ, Ij=wOb46r !"o2~}d#)?!/ 5W K#~8M>elK\C߫W LƝv:R Wq]?$9>WzH^b7bY8k.H"þz_̱<īK01`_Вm˴6.vI2!-43R_ G3ʛa墳eo.! J1Z MTK9#QO [ |Jd H`Q}F6]ޱ!v&m4K1 7О'D+L~ @rIcEpjHFeBbr-8$pmbETZuiZypX8(F%V΍&0W`њH}I{_O\}`)P !"ϴtm' Jy7xFʑEԈc!xy^B405DgF/]O6zqLl~G `ٟ(oWƀLj'â]N'>aEKqB ʈڣ_1)?H#|~E5Z$%/n+>W0) |J (+$Z8=fbG\v{"`{څB}d 嵻cj6 ɘ(Q`:JܖzцQ33⡙/,tmM@! "`S~ʈW%蕥o\aҾk{ӟB')ֲ8zgI290GYNR҅uiKnb 螅4 # 50 A̲kee #ے_ad #fP%~p*'ҞUq;n.2T~;P7 PEx4o'|9̀^>! \,zlt >ʼn[\Z= L *4U"3duM}=U&{ t|hٯkJpjm F~3=v]( cҵȇ|QQh+J8|#&@vNҾBm4Gy^$+ӔNg VpU dП9N虲(40ٓY 9ͭO JqC'HiCl'R r«!"BI˲A!YؽǕrmR#Er{#M@^ \&]2dG@\@ Sn|XSKapʷ&yqH[PJt!zUbwa_mvЦ .V8y ѳ-$u"1YaL8Y XhMbdYcI-31jh Av qMɧ.m M ,8(Ą[gi@%Ѱ7̓!(2uШFV;vdz_"[Br%Eȸ`'lIi)>YKzz?7zӐہњ)'<{a[,á_au7IU#/JyEk-Xiѹ7Qf"du!fF1N4l9 2mD8hu*8;\ZYgc}\L"vYX^|"cՉh-T!۲2:)7"? 9r ugL}"3H@B(%0(%a.m;6+D#1>C炏3lVB yHwgLnFc0&a9zf'n-ʊ hF rDCDH2CW18^7æ`vGM};E.aѬEu'xF'{ʐTG?1Ͽ sGzD:"9R6šo^^Z SABnzbd-2.3.2/interfaces/Glitter/templates/static/bootstrap/fonts/glyphicons-halflings-regular.ttf0000644000000000000000000012042413217004753031626 0ustar 00000000000000FFTMhGDEF8 OS/2gKX`cmapHLjcvt ($fpgmS/,egaspglyf*ϣheadk6hhea 2$hmtxloca2Tzmaxp nameԾ|postAVXprep+.webfaR7 =].]} Z 2UKWN@ | dHN@ + / _ "&' ' )9IY`iy )9FIYiy * / _ "&' ' 0@P`bp 0@HP`pfߴh     xrlf`_YSMGA@(,KLPXJvY#?+X=YKLPX}Y ԰.-, ڰ +-,KRXE#Y!-,i @PX!@Y-,+X!#!zXYKRXXY#!+XFvYXYYY-, \Z-,"PX \\Y-,$PX@\\Y-, 9/- , }+XY %I# &JPXea PX8!!Ya RX8!!YY- ,+X!!Y- , Ұ +- , /+\X G#Faj X db8!!Y!Y- , 9/ GFa# #JPX#RX@8!Y#PX@e8!YY-,+X=!! ֊KRX #I UX8!!Y!!YY-,# /+\X# XKS!YX&I## I#a8!!!!Y!!!!!Y-, ڰ+-, Ұ+-, /+\X G#Faj G#F#aj` X db8!!Y!!Y-, %Jd# PX<Y-,@@BBKcKc UX RX#b #Bb #BY @RX CcB CcB ce!Y!!Y-,Cc#Cc#-(h ./<2<2/<2<23!%3#(@ (ddLL$/ 3Ͱ 2/ְ2Ͱ2+015!'737!!'#'7dȷȷȷȷLL J +/3Ͱ2 +@ + / ְ2 Ͱ2 +@  + +@ + +01!!!!!,p,ppd7v2/(Ͳ(2 +@(. +/!3Ͱ2/3Ͱ2/ Ͳ +@ +8/7ְ2"ͱ22"-+2.Ͱ29+"79- 2999017347#7367632#4.#"!!!!32>53#"'.'ddqd%Kup<3LJ9D?{dd 09C3JL3akw$B d/5dZgj7X0,Z>d.6dJtB+0W5ju.xL//+01!!|,,A/Ͱ /+  99013!2654&#".#"qOxx.,,nBUPrzxawי kdL 57% P,XX,dpX[ ,%'7'7764/&" MZfVc $ pQfV\ ' 1 3+Ͱ2 /ְͲ +@ + +@ + +01!!!5! ,,dd&L &7>5%&7>54&&$OAXX@JOWOFS  @JOn)`*^r67)Q7q  OY+/Ͱ//ְͰ+ͱ+$99 99$901 "'#" 6& N,mwȃȎwm,NldXD/ְͰͱ+014>>.d8Zwwy,0{xuX6Cy>>yC@vS-IDEH-Sv@9yUUyG !3! 7Hߒ p??G  /3Ͱ2/+01!3! 77'7#'HߒCIJMN p??t⌍155"&=462#%??%d3||3d L #'+/3+ͱ 22/"3Ͱ$2 /&3 Ͱ(2/*3Ͱ,2/.3Ͱ02/2334/ְͳ $2+ $2Ͱ2+2 ͳ$(,0$2 !+%)-1$2ͱ5+ 9999011!%35#535#535#535#535#!!5!!35#535#535#535#535#ddddddddddXXddddddddddLdddddddddd|d|dddddddddLL/?B +,3Ͱ$2/<3Ͱ42@/ְ2 Ͱ2  +02)Ͱ82A+015463!2#!"&463!2#!"&463!2#!"&463!2#!"&ppXpp2pmppmp LL/?O_ov +'+/Ͱ/#3Ͱ!2 +@& + +@ +/(/ְͰ&+2%Ͱ 2%& +@%# +&% +@& +%+ͱ)+&999%9$999$999901 "'#" 6& 53533##5N,mwȃFdddȎwm,NlYdddd]+/Ͱ/ /ְͰ+ͱ!+$99 99$901 "'#" 6& !5!N,mxȃFpȍym+MlY+E/ ,/ְͲ +@ + +Ͳ  +@  +-+ #$90147 654&'5".;2654&+"ҧg|b|g[՛[ddX(>7xx7>طv՛[[ d 0+ 33/ְͰ+ Ͱ  +ͱ+0173#33333d,dd,  PGQb/PͰK/6R/ְHͰHM+$ͱS+H =99M39$9$/99P99K!'E$96+A9901732?6?67'76?654/&/7&''&/&#"'462"&P-<-1&("/&./80PP,<-0&("/&2,;.P g~~~~Y!)&1,;.Q  Q,=,1&("-&3*:/QQ/:/.&0X~~XY~~d#'+/37!+$Ͳ(04222'/*26333Ͱ/ͱ,22// 8/ְ$Ͱ$%+2(Ͱ,2%( +@% +()+0Ͱ01+-24Ͱ 241 +@4 +45+ͱ9+015463!5463!2!2#!"&!#!"&73#3#!5!3#3#d ;),);  d;)D);ddddd,dddd2 d);;)d 2 n )<<)D,dD , +3 / ְͰ+ͱ +901 #!!!Y|pXd" +/ְͲ +@ ++017463!!#!"&d  X,~  ] ,  /Ͱ/Ͳ +@ +//ְ Ͱ +Ͳ +@ ++ͱ+  $9 $9 $9 $901$  $ 6& 33DVGdD_Vd .+3 / Ͱ/Ͳ +@ +2/+01#333!#3#d)(1,Pp,L J + Ͱ/ Ͱ2/ְͲ +@ + + ͱ+ 99  99011!3!3!%35#,ᯯ, pdc +Ͱ//ְͰ+Ͱ+ ͱ + $99 $9 $9014>2". 6& 333_ޠ__ޠ\TPȖޠ__ޠ__Td, a /Ͱ//ְ Ͱ +Ͱ+ͱ+  $99 $9$901$  $ 6& ##DVOD_Vb,, ) + ͱ22//+ 99015!3#!"&3!73!  2,2aD%  F /Ͱ//ְ Ͱ +ͱ+  $9$901$  $ 654& DV:)DS/ Ͱ//ְͰ + ͱ+ $9 99  $99012>5# &632!&#"[՛[nv՛՛[[vbQz[!z+/Ͳ +@ + /Ͳ  +@ +"/ְͰ+ͱ#+99 !$9 99!9  999014>327!7&#"!32653#"'[vƝppIp[vƝXv՛[zpPPv՛[z d #'P/3 Ͱ2 /3 Ͱ2/ 3Ͱ!2/$3Ͱ%2(/ֲ 222 Ͳ222)+013!!!%53'53'53'53!5!=!%5!%5!dLddddddddd   |dddddddddddddddddL#J+ / $/ְͲ +@ ++Ͳ +@ +%+ $901546;5463!232#!"&!54&+";)dvR,Rvd);;)|);,dX);RvvR;));;dLL+/ְͱ+0133>>7.ddd3&Ͱ62 /B/ְͰ"++Ͱ+2+;Ͱ;+ͱC+2+ $9&/$9 9901;2654> ;2654."46;2+"&%46;2+"& 2  2 cޣc   X     ,rr  ,tޣcct 4  4 X!!7'77',,GGG GGGp/ְ ͱ+01!!%7'654,,EojCV 956nb<//ְ Ͱ +ͱ+ $9 $901!%%7'65477654/,,EojCV^{wQ57nB !/3?CGKO+0D33Ͳ)1E222/'+L333Ͳ%-M222"/33#Ͱ2/H33!ͱ4I22P/ֱ22ͱ220+ ,223Ͱ523. +*2%Ͱ@2.% +@." + 222%7+DH22;ͱ&J22;L+B2OͲ9=F222Q+04?$97%()8999"89$9#:;999@ 67<=@C$9011!#5##535!535#!!!5335#5!3##5#5355333!5#53!!5!5353dddd d,,dddd,,ddddddd,,,ddddddddd,,,ddd ddddd dddp,ddddDdd  #p +333 ͱ22 +$/ְ Ͱ + 2ͰͰ +Ͱ +Ͱ +#ͱ%+ 99990153#5!'353'3535353'3ddd,ddddddPdd[[[[[[)+//ְ ͱ+ 99901463! 2764'&"  SS D TT1+3/Ͱ2/ְ ͱ+ $901463! 2764'&"%3 '  TT d 2 D TTD 2d ?+/ /ְ Ͱ +ͱ + 9999990137!!!dddddL 3 4&#!"E~ 'Y%+Ͱ /Ͳ  +@ +2 +@ +2(/ְ Ͱ2 +2ͱ)+  '"$90153!73#5!!7.#!"7>3!2#!"&dXd5(P>^ > B&  & dD||Z   dL%-1o/%Ͱ)/-Ͱ!/2/ְͲ +@/ +'++ͱ3+9+'!$% $9-)"#$9!.199 /0$90153!2654&+.+"#"462"264&"%53;));;)37S*)R:. );dȐ>X>>XXd);;)X);E5+);;;)pȐȐ X>>X>^dd5"+ 3Ͳ 222#/$+013!5".?!#!5&'./#5m)>$\R+5"(]q *k.tB6,-WBB*. 0 Ɍd )1e +!Ͳ +Ͱ)/*Ͱ1/ Ͱ  2/ְ!Ͱ*2!.+Ͱ% ͱ3+%.9)!9*9190135>54.'5!2#'32654&+532654&#d); $x!" E4+vOȡY}^LlY3(; F7]7( 3AvFTMaTZd{MRao +Ͱ2 /3 /+0135>76&'.'5!Ms (G !:" 0G9C/Q8$99#'% 4<9 %~+/333 Ͳ +@ + 2&/ְͰ +%Ͱ%+Ͳ +@ + +@ ++ͱ'+ 99 9 901'3#7#33!3#4.+!57#"KKK}}KK}2.!"dpd"!/ c,' 2dd2R '! %+Ͱ/3 Ͳ +@ +2&/ ְ%Ͱ%+Ͳ +@ + +@ ++ͱ'+% $9$99999901?!55!3!3#4.+!57#"! d2/!"dpd"!.3}KK}}KK,' v2dd2 'L/?53!26=4&#!"53!26=4&#!"53!26=4&#!"53!26=4&#!"L X2ddddL/?53!26=4&#!"3!26=4&#!"3!26=4&#!"3!26=4&#!"LLDD2ddpddL/?& +Ͱ-/$Ͱ/Ͱ=/4@/A+01=463!2#!"&5463!2#!"&5463!2#!"&5463!2#!"&Ld X2ddlddddlddL/?& +Ͱ/Ͱ-/$Ͱ=/4@/A+01=463!2#!"&5463!2#!"&5463!2#!"&5463!2#!"&LLLL2dd@dd@dd@ddL/?O_oR +L3ͰD2/\3ͰT2-/l3$Ͱd2=/|34Ͱt2/ֲ 0222 Ͳ(8222+01=46;2+"&546;2+"&546;2+"&546;2+"&5463!2#!"&5463!2#!"&5463!2#!"&5463!2#!"&dddddddd,    2dd@dd@dd@dddd@dd@dd@ddL *:J /&3Ͱ.2K/L+90153553#3!26=4&#!"53!26=4&#!"53!26=4&#!"5;26=4&+"eɦddX, dddK}}K LddddL/?CJ@+K/@ְCͱL+0173!26=4&#!"53!26=4&#!"53!26=4&#!"5;26=4&+"3535#5X, dd d!2ddddL&}KdK- /Ͱ/ְ ͱ+ 9 9901463!2#!"& ,,,,,,,v,,d,LY +/Ͱ/ /ְͰ+Ͱ+ ͱ!+999 9999015463!2#!"&?'!462"Xd*J%lNpNNp, >pNNpN= +//ְͰ+ͱ + 99 999014>32.'&73264&"yz{yII99 "c]s+?—jk֖|ׁ~rBB "koKk֖I +Ͱ//ְͰ+ ͱ+ 99  99 $9014>2".3"_ޠ__ޠMޠ__ޠ__ Vu%4>7.77.'&6?uDmssIOWM?%N~OrÀ~[[.  \7^`GvwsuEYd;^RlbJ(I43nh!&W+Ͱ/'/ְ Ͱ +ͱ(+  $9"99!$9 "#%$901463!"3!26=7#!"&%7' 7/n);;));ԥrkqq\,;) );;)}j2qkqqUL.H+Ͱ"/'Ͱ /Ͱ//ְ ͱ0+"$999 %9&901463!#"3!2657#!"&> "U);;));ԥgg_hHCVC9,P X;) );;)5!&4 D>3CmL#R+Ͱ /$/ְ Ͱ +ͱ%+ "$9!9 "#$9 !9901463!2!"3!26=7#!"& '',:323>54.#"35#DȐ '-"#1D1iD젠  =& )2X23L(pd ; / Ͱ/3Ͱ/Ͱ//+999901$  $7!5#!3#35#DddddD젠d,dd1i+/!Ͱ2/#333Ͳ%/2222/ֲ+222Ͳ )2223+$%01$99!9 *+9990153>7533##5.'35367#53.'#53*EkI6vkYȌ`oKȕ4fIKn8dtap;Dsd7>;pac//+901!!XX#c//+901! XX,,;@-J+/ְͱ+901 !!XXXh+/ְͱ+901!!!h(,*?XXL 5>7 FX_Ȅխg;@-$Du +/+011!&ځ&p&ځ &"# 7'!' "''ف'p5'ق#O / Ͱ#/Ͱ/$/ְͰ+ ͱ%+ !#$9# 9999014>2".;2676&+"35#[՛[[՛V:#6#:0՛[[՛[[F.d&*04;3'+13*Ͱ227>7.#676%>7>'&" 8./ieh,Jhqx{\Sc'C78Fak[)!#==Y57>'>7>76''&'.7.7o FFB:8( OV $9DkC@&'GOS3 *gJ.  &:4?B8- %>=B'Pd!I,  =CnCSm,U!ٕfmS ;4( .MV .n}3!?GC/)Ͱ:/ H/<ְ7ͱI+7<@ )(5>@C$9 :$.5>BG$9017>2".'72>7.'"&5477./=FOsvvsOFFOsvvsOFC-[TzwRY,H 7:91.f1ii%LX( (WT`G//G`TW( (( (WT`G//G`TW( ( `=^8+(3\;hI%E:JY||UIWs|Ci`$$ )A+3B/C+6=+ .    + + + +$ +% + #999$9%9 9 $%........@ $%..........@017>3273#7.'77.547?./7>7&'7=FOsvH=<%Ɣ%Rri' ҷ%k.f1i/:(&-/"0/a+'C. %ZeX( (WT`G/Pegy8(6nUIWs|C/WR&2&?@06@(( 4kbf &3!26'.7 !5#5#o%%~8~ddDDG  ! d-dd,dd)H/ */%ְ2Ͱ 2% +@ +% +@%# +++%99 %99015467462'%/#&=47&dkX|Xkd^^d)1ES>XX>1) [@ NN @[ L #'+/37;?CGKOSW53!265!5!54&+5#!5##"53'53'5353'53'5353'53'5353'53'5353'53'53Ld ddddddddddddddddddddddddddddddd2dddddJddddddpddddddpddddddpddddddpddddddx A/3Ͱ2 /3Ͱ2/+99  $99901=!35 5# !7'!735 5#X,ԟzz,XXz{L+/ 3/+01463!2#!#"&;));;)d);X);;));,;dL%)-`+ Ͳ  +@  +2&/*3'Ͱ+2./ְ&2Ͱ(2+*2Ͱ,2/+$9999015!32>'4=!".!!!d,U'5%;) ,'MeeM',,Xq \ #(,.*R~jqP33Pqj~RV,,h 7`aaCF ' FDBCa:dv(//ְͱ+9901 #!!!# #+,}++pX,pX2F"+3,Ͱ,&ͱ22//Ͱ/ 3/$ְͰ+ͱ4+-901&763!7>;2++"&=!"&=#"&5463!7!"&'&^6**20 -*? 2222*L +Ͱ/Ͱ 2 /+011!53463!2!P;),); d);;)dL(+Ͱ/ Ͱ2 /+9013! 3463!2!!,P;),);DX);;). ! + /ְͱ + 99013# #3.**,X,/ / / +9901!5 5!,X,X*!I +Ͱ2/ 3Ͱ/"/ְͰ+ Ͳ +@ +#+ 901=463!2#!"&>3!235#35#;));;));$%dddddd);;)d);;U'-$ddddL %3&4/ְͰ&+.ͱ5+& 9901546?.5454>;%%##"+"&'4632#"&e2" ]&/ S8X22 !U  QRJf'/5++/Ͱ%/3Ͱ2% +@%" +0/1+%/(-990146;7>7'&6;232"&/.267"Jv?zS^Sz?vR:: 8F8 0l^GM~ %M( .))1==1777'7'7'7'''N--N괴N--N-N鳳N-,N鴴N,d".//(ְͱ0+(90153#;;276=4&#!6=4&+"?3!#',d={.%='='20`dd22ֈXKd9X+d,Qv,Q(%wկ}dL".p+%Ͱ/3(Ͱ./Ͱ2,/ //ְͰ+#Ͱ#&+Ͱ)+ͱ0+&#(,9999)+9.*901374;6;2#!+"&/&735'!5##dd={.%='='20`dd22ֈdX}Kd9+d,Qv,Q(%կ}wddU"Ay /$Ͱ/)Ͱ1/Ͱ21 +@1 +B/ְͰ+#Ͱ#-+Ͳ- +@-< +C+-# ?$9$#9)91;2654&#!*.'&54?'dj  m U.UkmTkdd%7   VXK %  pyLN'YS(  SeV8<y/$Ͱ/Ͱ8/Ͱ:28 +@89 +=/ְͲ +@, +&+Ͱ9+<ͱ>+& )$9$&998',9990146!'&54?632#!"&'#"'32!7%*#!3elU.U m  m!jT %jW   $CLy q  ' (Sd)YS   XaL6:G7+8;/ְ72)Ͳ) +@): +32)/+ͱ<+)699/9013!2654&'%54&"'&77><546!5!a ' (NLy%p[S22(SY XVjTnkUT  n V   dp 26E3/47/ְ32)Ͳ) +@)6 +2)%+ ͱ8+) 99 % 901?26=%>54&#!"!&5<.'&5!p &yMNS) % Y(22XIn  UTlnTjVSdڂ  q: +Ͱ//ְͱ+  999999014>32 $%! !_z',nUzݠ_A&*8+Ͱ//ְ ͱ+9 9999014>32 $75!5!5_yzݠ_.Uzݠ__z>+/ְͰ+ ͱ+9999  99014>32 $%333_zyݠ_'Uzݠ__z,M+//ְͰ+ ͱ+9999  99 999014>32 $% ##_zyݠ_',,Uzݠ__zp,+,ͰQ///ְͰZ+ ͱ+9Z@!#$>LWz$9  "(2=\ix$9Q,28>HJWY$9@ Ztp$9wxz999014>32 $277>7.'.'"'&65.'6.'&76746'&67>7&72267.'6'?6.''&%>72>7._zyݠ_" X>9. #ex $/ F = .2) ( (%  )#? 7 .R+>>?1  B)Uzݠ__zY"v F  /K q$>   #/ & % I+ *  ' ) $#   ' "rq % 1' <7&6767'"/X!N` {+o+We6\e~\F/n`/37;P /4Ͱ7/Ͱ/0Ͱ3/Ͱ,/8Ͱ;/%Ͱ>D+Iͳ7ID+1Ͱ1/7ͰI+ͱO+& $9>*-<9971 /;$9 $9*-<>$9(99#/;9901$  $ 654& 462#"64632#"46?&54632#"'#"&%462#"&DVm. M  Q*z   73$%3 .  D.  ,! . 1~! . $33R . ;O:/'Ͱ /Ͱ6/JP/Q+'?9  1$9239901327>767>'&'&#"67632#"&'&>767>32>'.'&#"0#vF?8!@)'(#Z .C"|Ey&$4I7Z 0$&\4=k6_v[EC8fOESkZ(G־N9@1*+,#b/W""tCu$'$4B?#>@$$\475be[<C]W$!7GO6X6C4/.3Ͱ27/ְͰ++ ͱ8+9+$949014632632'.'.76?>54&#"'&#"Oƃbg#WCG`+rFB:5S%=>@]aRq @C>`:I:vr3I;cŁŃ.ZlGF:FA:5_=P&VA>Zo\o >FXGaSPc9w232764/&''7'&'7'7>54/&#"9BB]_@BB i{_.7BBi_.#7BB]_@Ba^BBBBB i{_-87B]Bi`.5#j+]BBB@E+Ͱ/Ͱ//ְͰ+ Ͱ Ͱ/+9990174>2#!"&7!!264&"+%Ͱ ͱC+09+'99 %8>A$99013'.54>753#.'#5&'.654&''WJ.BN/!XOd&ER<+6J@" MNW(k,;+@GdfH6//Ͱ/#3Ͱ!2/ Ͳ +@ +I/ְ>2Ͱ)2 +@# + +@ ++ͱJ+=GH$9 $%/68$919/62>991A990153&'.>7632#4.#"3#>36327#"&'>7>'d /-aʙDP$%T) ):#b "L<2)O'*2'V7   0 $Xd17;V^(Xw4K,9  %(d2;6 "B   7G  +/ ְ ͱ+ 901 ## ##****,,|X,| "+3 Ͳ+Ͱ/ͱ22 /Ͱ/Ͳ +@ +2"/Ͱ2#/ְͰ+ 22 ͱ22 + 22ͱ 22+Ͱ/ͱ$+999 901333!5335!##535!#5#735#d,cdc,dddd,|dddddd, dd"+ 33 /Ͱ"/Ͱ/ͰͰ/Ͱ/Ͱ2#/ְͰ+22ͱ22 + 22 ͱ22 +Ͱ/ͱ$+99"$99901333!!#5#5335!##53535#,dddd,cdccdd,| dddddddd|L k + /Ͱ/Ͱ /Ͳ  +@  +/ְͳ+Ͱ/ 3Ͱ + 2 ͱ+ $9 9901 ##!#553#35#**X,dddd,,| dd |L k +/Ͱ/Ͳ +@ +// ְ ͳ + Ͱ /3Ͱ  +2ͱ+ $99901 ##%53#!#5'35#**Xdd,dcdd,,|dd  dd R/Ͱ / Ͱ/Ͱ//ֲ 222ͰͲ +@ +@ ++ $901 ##5!5!5!53** p,,,|,,, R/Ͱ / Ͱ/Ͱ// ֲ222Ͱ Ͳ +@  +@  ++ $901 ##535!5!5!**,p,,|,,,LL* +Ͱ/ /ְͰ+ ͱ!+01463!2#!"&73!2654&#!",ԥ;));;) );,ԥA);;));;)LL"> +Ͱ/#/ְͰ+ ͱ$+ !99 "9901463!2#!"&73!2654&#!"-,ԣ;));;) );M,ԥA);;));;) LL"> +Ͱ/#/ְͰ+ ͱ$+ "99 !9901463!2#!"&73!2654&#!",ԥ;));;) );d,ԥA);;));;)dMLL"> +Ͱ/#/ְͰ+ ͱ$+ !99 "9901463!2#!"&73!2654&#!"!,ԥ;));;) );d,Ԣ?);;));;)pML<+Ͱ/Ͱ// ְͱ+99901!5 55!2654&#!5!2#,p);;) ,p;));ԥ /ְͱ!+9013!276'&!676/#" .    LJ v  XL?+ͰͰ/Ͱ/Ͱ /ְ ͱ!+999013!275!"&5463!5./"!5 5,/5 );;)]]X,p;));,$T+Ͱ/%/ְͰ +ͱ&+  $$9#9 "#$$99013!26='#!"&546;7'#"%'!',Nz;) );;)vJdabI{);;));zN V  Z /Ͱ/Ͱ//ְ Ͱ +Ͱ+ͱ+ $9 $901$  $ 6& 462"DVrrrD_VrrrL . +Ͱ/Ͱ 2/ְͲ +@ ++011463!2 !!35#  dd   pv2L + +Ͱ//ְͲ +@ ++011463!2!!! 35#  ,,'C^dd  ,2L . +Ͱ//ְ 2Ͳ +@ ++011463!2 ''35#  1TFdd  TF:2L + +Ͱ//ְͲ +@ ++011463!27'!'35#  aapԕdd  baԕ 2L . +Ͱ//ְ2Ͳ +@ ++011463!27'735#  |bԕcdd  daԔ2+ /ְͱ +01  %O`w8dLM/Ͳ +@ +2 +@ +2/ְͰͰ+ ͱ+ 99901546;!3+!#"&35#dDXdd,pg>@/Ͳ +@ + +@ +2/ְͰͱ+ 99901546;!3'!#"&%735#dx~E{xa{%dd,xp{x`{$#$/ְͰͱ%+01546;!3'!#"&35#7'77'dgXddd,gpgժl/Ͳ +@ + Ͱ/ͱ22/ְͲ +@ +Ͱ+Ͱ 2+9 99 901546;!3!!#"&% ##53dp X,,d,p,,[/Ͳ +@ +/ͱ22/ְͰͰ+ͱ+9 9 999 901546;!3'!#"&%333 53dnXd,np,,L 53!265!5!54&#!"5!LPd&df /33ͱ22/ 33ͱ 22/ְ Ͱ  +Ͱ+ͱ+ $9$9$9999901!!5335335!5 553;5#,pdddd,ddddd* d/:+0/ְͰ +ͳ +Ͱ/ Ͱ +ͱ1+0173737+"&5%;2654&d22d22d22dX $%dd,dd,ddpAd5!sRuEdL38+ 33Ͳ 222(/%333'Ͱ24/5+(3 99013!5"&5!#!5".546?5!2!4635!2dKK"2pK Kp"28 &v& 88 x88 &v& 88 LL *.2+Ͱ/Ͳ +@ +//0+$9013!2654&#!"!73%!!5!5!!%35!'!5%;),);;));di'Wdd,,'iWd,);;));;)Dbd,,bbdF!3?6&/&&'&'7>/.>fgї{4w|~ev-+fg=!/vg|~v1L@/+ Ͱ(/8A/B+  /99(&)2@$901=46754>2#!"&?>=6 6=.#"m&RpR&m>d|~\ud?, 23/2  23!""!A1)!((! dL+/+0135!%!'57##5##5##5#dL}dddddddddȖdpddL $ +3/ ְͰ+ͱ+013!4&+"46;2346;2d,;)d);;)d);d;)d););;)p);;));;)DL'+H +Ͱ/,/ְͰ+ ͱ-+ #(*$9 &()$901463!2#!"&7!!!#535!3#353#5#3d|||D||d,dddd,|| |,ddddd,dp,L'+H +Ͱ/,/ְͰ+ ͱ-+ #(*$9 &()$901463!2#!"&7!!3533##5#353#5#3d|||D||ddddddddddd,|| | d,dp,L#D +Ͱ/$/ְͰ+ ͱ%+$9"$901463!2#!"&7!!!5#35!!5#35!d|||D||d,,,|| |d,d d,dLD +Ͱ//ְͰ+ ͱ+$9$901463!2#!"&7!!-d|||D||d,d,,|| |,ԖL'Z +Ͱ/Ͱ#2/%3Ͱ/(/ְͰ+Ͱ+!Ͱ!$+Ͱ+ ͱ)+01463!2#!"&7!!!%3264&+;#"d|||D||d)69&6)&,|| | dTVVT,L#)H +Ͱ/*/ְͰ+ ͱ++ !$'$9 "&($901463!2#!"&7!!!#535!3#35#33#d|||D||d,ddcdd,|| |,ddddd,pL!'L +Ͱ/(/ְͰ+ ͱ)+"%$9 $&$901463!2#!"&7!!!#5#5335#33#d|||D||d,dedddcdd,|| |dpdd,pL!%+ +Ͱ/")33Ͱ#2/Ͱ/&3Ͱ'2/,/ְͰ+2!Ͱ!+ͳ+Ͱ/Ͱ"+%Ͱ%*+)Ͱ)&Ͱ&/)+ ͱ-+9901463!2#!"&7!!5!##53553!5353#d|||D||d,cdcd,dd,|| |dddpddddd  y /Ͱ/Ͱ/Ͱ//ְ Ͱ +Ͱ+ͱ+ $9 $9 $99 $901$  $ 6& 57!!!!DVd,,D_Vddd  $ /Ͱ!/3"Ͱ/Ͱ/%/ְ Ͱ + Ͱ2  +@  + !+2$Ͱ2$+ͱ&+  $9!9$ $9"! $9999 $901$  $ 6& !#5#3#353DV,dddD_VddddddddA!q/Ͱ Ͱ2"/ְͰ+Ͱ+ ͱ#+999!99  99 $999901;!32654&#".#"333qOxx.,,nBU:Pr,Ԭzxawי k,A /ְͱ!+99901; >54&#".#" ##qO^yx.,,nBU:,,Prmdyawי k,,dLm7!!'5!33 33dK^KԪț--,,My7)327!'32654'>54&'.#"&#"y9/iJ8,K^K.6Ji 2;{Y^t Ji5XJi--2iJ f=ZYqtiA.X_<]}]}::(dFHFddjdddddd5d!u,dh"oddF:.JadO9'ddddddy****f0H|6,Lrd"DL 0 ` D V @  x <bN&` `$`J6*Hz.L X0 D  ( D l !h!"@"#|#$$$%%%%%&X&&&' 'h'(0(\().)*f*+^++,8,--.^../2001"1x1223Z34445`566V677Z778@899H99::L:t:;;b;<.6>>???@N@AAvABpBCvCD*DND j (|  L 8 x6 6   $ $4 $X | 0www.glyphicons.comCopyright 2013 by Jan Kovarik. All rights reserved.GLYPHICONS HalflingsRegular1.001;UKWN;GLYPHICONSHalflings-RegularGLYPHICONS Halflings RegularVersion 1.001;PS 001.001;hotconv 1.0.70;makeotf.lib2.5.58329GLYPHICONSHalflings-RegularJan KovarikJan Kovarikwww.glyphicons.comwww.glyphicons.comwww.glyphicons.comWebfont 1.0Mon Sep 16 15:54:37 20132       !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~glyph1uni000Duni00A0uni2000uni2001uni2002uni2003uni2004uni2005uni2006uni2007uni2008uni2009uni200Auni202Funi205FEurouni2601uni2709uni270FuniE000uniE001uniE002uniE003uniE005uniE006uniE007uniE008uniE009uniE010uniE011uniE012uniE013uniE014uniE015uniE016uniE017uniE018uniE019uniE020uniE021uniE022uniE023uniE024uniE025uniE026uniE027uniE028uniE029uniE030uniE031uniE032uniE033uniE034uniE035uniE036uniE037uniE038uniE039uniE040uniE041uniE042uniE043uniE044uniE045uniE046uniE047uniE048uniE049uniE050uniE051uniE052uniE053uniE054uniE055uniE056uniE057uniE058uniE059uniE060uniE062uniE063uniE064uniE065uniE066uniE067uniE068uniE069uniE070uniE071uniE072uniE073uniE074uniE075uniE076uniE077uniE078uniE079uniE080uniE081uniE082uniE083uniE084uniE085uniE086uniE087uniE088uniE089uniE090uniE091uniE092uniE093uniE094uniE095uniE096uniE097uniE101uniE102uniE103uniE104uniE105uniE106uniE107uniE108uniE109uniE110uniE111uniE112uniE113uniE114uniE115uniE116uniE117uniE118uniE119uniE120uniE121uniE122uniE123uniE124uniE125uniE126uniE127uniE128uniE129uniE130uniE131uniE132uniE133uniE134uniE135uniE136uniE137uniE138uniE139uniE140uniE141uniE142uniE143uniE144uniE145uniE146uniE148uniE149uniE150uniE151uniE152uniE153uniE154uniE155uniE156uniE157uniE158uniE159uniE160uniE161uniE162uniE163uniE164uniE165uniE166uniE167uniE168uniE169uniE170uniE171uniE172uniE173uniE174uniE175uniE176uniE177uniE178uniE179uniE180uniE181uniE182uniE183uniE184uniE185uniE186uniE187uniE188uniE189uniE190uniE191uniE192uniE193uniE194uniE195uniE197uniE198uniE199uniE200KPXYF+X!YKRX!Y+\XY+R7aSABnzbd-2.3.2/interfaces/Glitter/templates/static/bootstrap/js/bootstrap.min.js0000644000000000000000000010772013217005257025750 0ustar 00000000000000/*! * Bootstrap v3.3.5 (http://getbootstrap.com) * Copyright 2011-2015 Twitter, Inc. * Licensed under the MIT license */ if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.5",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.5",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.5",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.5",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.5",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth

',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.5",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'

'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.5",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.5",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);SABnzbd-2.3.2/interfaces/Glitter/templates/static/javascripts/date.min.js0000644000000000000000000014735313217005257024556 0ustar 00000000000000/** * @overview datejs * @version 1.0.0-rc3 * @author Gregory Wild-Smith * @copyright 2015 Gregory Wild-Smith * @license MIT * @homepage https://github.com/abritinthebay/datejs */ /* 2015 Gregory Wild-Smith @license MIT @homepage https://github.com/abritinthebay/datejs */ (function(){var h=Date,f=Date.CultureStrings?Date.CultureStrings.lang:null,d={},c={getFromKey:function(a,b){var e;e=Date.CultureStrings&&Date.CultureStrings[b]&&Date.CultureStrings[b][a]?Date.CultureStrings[b][a]:c.buildFromDefault(a);"/"===a.charAt(0)&&(e=c.buildFromRegex(a,b));return e},getFromObjectValues:function(a,b){var e,g={};for(e in a)a.hasOwnProperty(e)&&(g[e]=c.getFromKey(a[e],b));return g},getFromObjectKeys:function(a,b){var e,g={};for(e in a)a.hasOwnProperty(e)&&(g[c.getFromKey(e,b)]= a[e]);return g},getFromArray:function(a,b){for(var e=[],g=0;gb?1:0;throw new TypeError(a+" - "+b);};h.equals= function(a,b){return 0===a.compareTo(b)};h.getDayName=function(a){return Date.CultureInfo.dayNames[a]};h.getDayNumberFromName=function(a){var b=Date.CultureInfo.dayNames,e=Date.CultureInfo.abbreviatedDayNames,g=Date.CultureInfo.shortestDayNames;a=a.toLowerCase();for(var m=0;me?!1:!0};h.validateMillisecond=function(a){return c(a,0,999,"millisecond")};h.validateSecond=function(a){return c(a,0,59,"second")};h.validateMinute=function(a){return c(a,0, 59,"minute")};h.validateHour=function(a){return c(a,0,23,"hour")};h.validateDay=function(a,b,e){return void 0===b||null===b||void 0===e||null===e?!1:c(a,1,h.getDaysInMonth(b,e),"day")};h.validateWeek=function(a){return c(a,0,53,"week")};h.validateMonth=function(a){return c(a,0,11,"month")};h.validateYear=function(a){return c(a,-271822,275760,"year")};h.validateTimezone=function(a){return 1==={ACDT:1,ACST:1,ACT:1,ADT:1,AEDT:1,AEST:1,AFT:1,AKDT:1,AKST:1,AMST:1,AMT:1,ART:1,AST:1,AWDT:1,AWST:1,AZOST:1, AZT:1,BDT:1,BIOT:1,BIT:1,BOT:1,BRT:1,BST:1,BTT:1,CAT:1,CCT:1,CDT:1,CEDT:1,CEST:1,CET:1,CHADT:1,CHAST:1,CHOT:1,ChST:1,CHUT:1,CIST:1,CIT:1,CKT:1,CLST:1,CLT:1,COST:1,COT:1,CST:1,CT:1,CVT:1,CWST:1,CXT:1,DAVT:1,DDUT:1,DFT:1,EASST:1,EAST:1,EAT:1,ECT:1,EDT:1,EEDT:1,EEST:1,EET:1,EGST:1,EGT:1,EIT:1,EST:1,FET:1,FJT:1,FKST:1,FKT:1,FNT:1,GALT:1,GAMT:1,GET:1,GFT:1,GILT:1,GIT:1,GMT:1,GST:1,GYT:1,HADT:1,HAEC:1,HAST:1,HKT:1,HMT:1,HOVT:1,HST:1,ICT:1,IDT:1,IOT:1,IRDT:1,IRKT:1,IRST:1,IST:1,JST:1,KGT:1,KOST:1,KRAT:1, KST:1,LHST:1,LINT:1,MAGT:1,MART:1,MAWT:1,MDT:1,MET:1,MEST:1,MHT:1,MIST:1,MIT:1,MMT:1,MSK:1,MST:1,MUT:1,MVT:1,MYT:1,NCT:1,NDT:1,NFT:1,NPT:1,NST:1,NT:1,NUT:1,NZDT:1,NZST:1,OMST:1,ORAT:1,PDT:1,PET:1,PETT:1,PGT:1,PHOT:1,PHT:1,PKT:1,PMDT:1,PMST:1,PONT:1,PST:1,PYST:1,PYT:1,RET:1,ROTT:1,SAKT:1,SAMT:1,SAST:1,SBT:1,SCT:1,SGT:1,SLST:1,SRT:1,SST:1,SYOT:1,TAHT:1,THA:1,TFT:1,TJT:1,TKT:1,TLT:1,TMT:1,TOT:1,TVT:1,UCT:1,ULAT:1,UTC:1,UYST:1,UYT:1,UZT:1,VET:1,VLAT:1,VOLT:1,VOST:1,VUT:1,WAKT:1,WAST:1,WAT:1,WEDT:1,WEST:1, WET:1,WST:1,YAKT:1,YEKT:1,Z:1}[a]};h.validateTimezoneOffset=function(a){return-841a}})(); (function(){var h=Date,f=h.prototype,d=function(a,b){b||(b=2);return("000"+a).slice(-1*b)},c=function(a){var b={},e=this,g,c;c=function(b,g,c){if("day"===b){b=void 0!==a.month?a.month:e.getMonth();var d=void 0!==a.year?a.year:e.getFullYear();return h[g](c,d,b)}return h[g](c)};for(g in a)if(Object.prototype.hasOwnProperty.call(a,g)){var d="validate"+g.charAt(0).toUpperCase()+g.slice(1);h[d]&&null!==a[g]&&c(g,d,a[g])&&(b[g]=a[g])}return b};f.clearTime=function(){this.setHours(0);this.setMinutes(0); this.setSeconds(0);this.setMilliseconds(0);return this};f.setTimeToNow=function(){var a=new Date;this.setHours(a.getHours());this.setMinutes(a.getMinutes());this.setSeconds(a.getSeconds());this.setMilliseconds(a.getMilliseconds());return this};f.clone=function(){return new Date(this.getTime())};f.compareTo=function(a){return Date.compare(this,a)};f.equals=function(a){return Date.equals(this,void 0!==a?a:new Date)};f.between=function(a,b){return this.getTime()>=a.getTime()&&this.getTime()<=b.getTime()}; f.isAfter=function(a){return 1===this.compareTo(a||new Date)};f.isBefore=function(a){return-1===this.compareTo(a||new Date)};f.isToday=f.isSameDay=function(a){return this.clone().clearTime().equals((a||new Date).clone().clearTime())};f.addMilliseconds=function(a){if(!a)return this;this.setTime(this.getTime()+1*a);return this};f.addSeconds=function(a){return a?this.addMilliseconds(1E3*a):this};f.addMinutes=function(a){return a?this.addMilliseconds(6E4*a):this};f.addHours=function(a){return a?this.addMilliseconds(36E5* a):this};f.addDays=function(a){if(!a)return this;this.setDate(this.getDate()+1*a);return this};f.addWeekdays=function(a){if(!a)return this;var b=this.getDay(),e=Math.ceil(Math.abs(a)/7);(0===b||6===b)&&0a){for(;0>a;)this.addDays(-1),b=this.getDay(),0!==b&&6!==b&&a++;return this}if(5 b)this.moveToLastDayOfMonth(),this.is().weekday()&&(b+=1);else return this;return this.addWeekdays(b)}var e=0;if(0a)return a=(a-1E4).toString(),a.charAt(0)+a.substr(2);a=(a+1E4).toString();return"+"+a.substr(1)};f.getElapsed=function(a){return(a||new Date)-this};f.set=function(a){a=c.call(this, a);for(var b in a)if(Object.prototype.hasOwnProperty.call(a,b)){var e=b.charAt(0).toUpperCase()+b.slice(1),g,d;"week"!==b&&"month"!==b&&"timezone"!==b&&"timezoneOffset"!==b&&(e+="s");g="add"+e;d="get"+e;"month"===b?g+="s":"year"===b&&(d="getFullYear");if("day"!==b&&"timezone"!==b&&"timezoneOffset"!==b&&"week"!==b&&"hour"!==b)this[g](a[b]-this[d]());else if("timezone"===b||"timezoneOffset"===b||"week"===b||"hour"===b)this["set"+e](a[b])}a.day&&this.addDays(a.day-this.getDate());return this};f.moveToFirstDayOfMonth= function(){return this.set({day:1})};f.moveToLastDayOfMonth=function(){return this.set({day:h.getDaysInMonth(this.getFullYear(),this.getMonth())})};var b=function(a){switch(1*a){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th"}},e=function(a){var b=Date.CultureInfo.formatPatterns;switch(a){case "d":return this.toString(b.shortDate);case "D":return this.toString(b.longDate);case "F":return this.toString(b.fullDateTime);case "m":return this.toString(b.monthDay); case "r":case "R":return a=this.clone().addMinutes(this.getTimezoneOffset()),a.toString(b.rfc1123)+" GMT";case "s":return this.toString(b.sortableDateTime);case "t":return this.toString(b.shortTime);case "T":return this.toString(b.longTime);case "u":return a=this.clone().addMinutes(this.getTimezoneOffset()),a.toString(b.universalSortableDateTime);case "y":return this.toString(b.yearMonth);default:return!1}},g=function(a){return function(e){if("\\"===e.charAt(0))return e.replace("\\","");switch(e){case "hh":return d(13> a.getHours()?0===a.getHours()?12:a.getHours():a.getHours()-12);case "h":return 13>a.getHours()?0===a.getHours()?12:a.getHours():a.getHours()-12;case "HH":return d(a.getHours());case "H":return a.getHours();case "mm":return d(a.getMinutes());case "m":return a.getMinutes();case "ss":return d(a.getSeconds());case "s":return a.getSeconds();case "yyyy":return d(a.getFullYear(),4);case "yy":return d(a.getFullYear());case "y":return a.getFullYear();case "E":case "dddd":return Date.CultureInfo.dayNames[a.getDay()]; case "ddd":return Date.CultureInfo.abbreviatedDayNames[a.getDay()];case "dd":return d(a.getDate());case "d":return a.getDate();case "MMMM":return Date.CultureInfo.monthNames[a.getMonth()];case "MMM":return Date.CultureInfo.abbreviatedMonthNames[a.getMonth()];case "MM":return d(a.getMonth()+1);case "M":return a.getMonth()+1;case "t":return 12>a.getHours()?Date.CultureInfo.amDesignator.substring(0,1):Date.CultureInfo.pmDesignator.substring(0,1);case "tt":return 12>a.getHours()?Date.CultureInfo.amDesignator: Date.CultureInfo.pmDesignator;case "S":return b(a.getDate());case "W":return a.getWeek();case "WW":return a.getISOWeek();case "Q":return"Q"+a.getQuarter();case "q":return String(a.getQuarter());case "z":return a.getTimezone();case "Z":case "X":return Date.getTimezoneOffset(a.getTimezone());case "ZZ":return-60*a.getTimezoneOffset();case "u":return a.getDay();case "L":return h.isLeapYear(a.getFullYear())?1:0;case "B":return"@"+(a.getUTCSeconds()+60*a.getUTCMinutes()+3600*(a.getUTCHours()+1))/86.4;default:return e}}}; f.toString=function(a,b){if(!b&&a&&1===a.length&&(output=e.call(this,a)))return output;var c=g(this);return a?a.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g,c).replace(/\[|\]/g,""):this._toString()}})(); (function(){var h=Date,f=h.prototype,d=Number.prototype;f._orient=1;f._nth=null;f._is=!1;f._same=!1;f._isSecond=!1;d._dateElement="days";f.next=function(){this._move=!0;this._orient=1;return this};h.next=function(){return h.today().next()};f.last=f.prev=f.previous=function(){this._move=!0;this._orient=-1;return this};h.last=h.prev=h.previous=function(){return h.today().last()};f.is=function(){this._is=!0;return this};f.same=function(){this._same=!0;this._isSecond=!1;return this};f.today=function(){return this.same().day()}; f.weekday=function(){return this._nth?m("Weekday").call(this):this._move?this.addWeekdays(this._orient):this._is?(this._is=!1,!this.is().sat()&&!this.is().sun()):!1};f.weekend=function(){return this._is?(this._is=!1,this.is().sat()||this.is().sun()):!1};f.at=function(a){return"string"===typeof a?h.parse(this.toString("d")+" "+a):this.set(a)};d.fromNow=d.after=function(a){var b={};b[this._dateElement]=this;return(a?a.clone():new Date).add(b)};d.ago=d.before=function(a){var b={};b["s"!==this._dateElement[this._dateElement.length- 1]?this._dateElement+"s":this._dateElement]=-1*this;return(a?a.clone():new Date).add(b)};var c="sunday monday tuesday wednesday thursday friday saturday".split(/\s/),a="january february march april may june july august september october november december".split(/\s/),b="Millisecond Second Minute Hour Day Week Month Year Quarter Weekday".split(/\s/),e="Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter".split(/\s/),g="final first second third fourth fifth".split(/\s/);f.toObject=function(){for(var a= {},g=0;ge)throw new RangeError(h.getDayName(a)+ " does not occur "+b+" times in the month of "+h.getMonthName(e.getMonth())+" "+e.getFullYear()+".");return this}return this.moveToDayOfWeek(a,this._orient)}},k=function(a,b,e){for(var g=0;ga.length&&0>a.indexOf(".")&&0>a.indexOf("/"))return e.year= a,h.processTimeObject(e);a=a.match(this.regex);if(!a||!a.length)return null;for(b=0;bp;p++){var q=c.shift();q&&(delete e[q],g--)}try{f=e[l]=e[l]||a.call(this,l)}catch(s){f=e[l]=s}g++;c.push(l);if(f instanceof h.Exception)throw f;return f}},any:function(){var a=arguments;return function(e){for(var g=null,c=0;cthis.hour&&Date.Config.strict24hr)throw"Invalid hour and meridian combination";"p"===this.meridian&&12>this.hour?this.hour+=12:"a"===this.meridian&&12===this.hour&&(this.hour= 0)}};h.Translator={hour:function(c){return function(){this.hour=Number(c)}},minute:function(c){return function(){this.minute=Number(c)}},second:function(c){return function(){this.second=Number(c)}},secondAndMillisecond:function(c){return function(){var a=c.match(/^([0-5][0-9])\.([0-9]{1,3})/);this.second=Number(a[1]);this.millisecond=Number(a[2])}},meridian:function(c){return function(){this.meridian=c.slice(0,1).toLowerCase()}},timezone:function(c){return function(){var a=c.replace(/[^\d\+\-]/g, "");a.length?this.timezoneOffset=Number(a):this.timezone=c.toLowerCase()}},day:function(c){var a=c[0];return function(){this.day=Number(a.match(/\d+/)[0]);if(1>this.day)throw"invalid day";}},month:function(c){return function(){this.month=3===c.length?"jan feb mar apr may jun jul aug sep oct nov dec".indexOf(c)/4:Number(c)-1;if(0>this.month)throw"invalid month";}},year:function(c){return function(){var a=Number(c);this.year=2h.getDaysInMonth(this.year,this.month))throw new RangeError(this.day+" is not a valid value for days.");c=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.millisecond);100>this.year&&c.setFullYear(this.year);this.timezone?c.set({timezone:this.timezone}):this.timezoneOffset&&c.set({timezoneOffset:this.timezoneOffset});return c},finish:function(c){var a,b,e;c=c instanceof Array?f(c):[c];if(0===c.length)return null; for(a=0;ac?-1:1,k=Math.abs(c);this.setDays(Math.floor(k/864E5)*h);k%=864E5;this.setHours(Math.floor(k/36E5)*h);k%=36E5;this.setMinutes(Math.floor(k/6E4)*h);k%=6E4;this.setSeconds(Math.floor(k/1E3)*h);this.setMilliseconds(k%1E3*h)}else this.set(c,a,b,e,f);this.getTotalMilliseconds=function(){return 864E5*this.getDays()+ 36E5*this.getHours()+6E4*this.getMinutes()+1E3*this.getSeconds()};this.compareTo=function(a){var b=new Date(1970,1,1,this.getHours(),this.getMinutes(),this.getSeconds());a=null===a?new Date(1970,1,1,0,0,0):new Date(1970,1,1,a.getHours(),a.getMinutes(),a.getSeconds());return ba?1:0};this.equals=function(a){return 0===this.compareTo(a)};this.add=function(a){return null===a?this:this.addSeconds(a.getTotalMilliseconds()/1E3)};this.subtract=function(a){return null===a?this:this.addSeconds(-a.getTotalMilliseconds()/ 1E3)};this.addDays=function(a){return new d(this.getTotalMilliseconds()+864E5*a)};this.addHours=function(a){return new d(this.getTotalMilliseconds()+36E5*a)};this.addMinutes=function(a){return new d(this.getTotalMilliseconds()+6E4*a)};this.addSeconds=function(a){return new d(this.getTotalMilliseconds()+1E3*a)};this.addMilliseconds=function(a){return new d(this.getTotalMilliseconds()+a)};this.get12HourHour=function(){return 12this.getHours()?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator};this.toString=function(a){this._toString=function(){return null!==this.getDays()&&0a.toString().length?"0"+a:a};var b=this;return a?a.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g, function(a){switch(a){case "d":return b.getDays();case "dd":return b.p(b.getDays());case "H":return b.getHours();case "HH":return b.p(b.getHours());case "h":return b.get12HourHour();case "hh":return b.p(b.get12HourHour());case "m":return b.getMinutes();case "mm":return b.p(b.getMinutes());case "s":return b.getSeconds();case "ss":return b.p(b.getSeconds());case "t":return(12>b.getHours()?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator).substring(0,1);case "tt":return 12>b.getHours()?Date.CultureInfo.amDesignator: Date.CultureInfo.pmDesignator}}):this._toString()};return this};(function(c,a){for(var b=0;bc;)f();else for(;bp?1:-1;this.dates={start:arguments[0].clone(),end:arguments[1].clone()};d(q,l,p,this);var s=!1===(l.isDaylightSavingTime()===p.isDaylightSavingTime());s&&1===q?l.addHours(-1):s&&l.addHours(1);l=p-l;0!==l&&(l=new TimeSpan(l),this.set(this.years,this.months,l.getDays(),l.getHours(),l.getMinutes(),l.getSeconds(),l.getMilliseconds()))}return this};(function(a,b){for(var c=0;c').text(htmltxt).html().replace(/<br\/>/g, '
') } // Function to re-write 0:09:21=>9:21, 0:10:10=>10:10, 0:00:30=>0:30 function rewriteTime(timeString) { // Remove "0:0" from start if(timeString.substring(0,3) == '0:0') { timeString = timeString.substring(3) } // Remove "0:" from start else if(timeString.substring(0,2) == '0:') { timeString = timeString.substring(2) } return timeString } // How to display the date-time? function displayDateTime(inDate, outFormat, inFormat) { // What input? if(inDate == '') { var theMoment = moment() } else { var theMoment = moment.utc(inDate, inFormat) } // Special format or regular format? if(outFormat == 'fromNow') { return theMoment.fromNow() } else { return theMoment.local().format(outFormat) } } // Keep dropdowns open function keepOpen(thisItem) { // Make sure we clicked the a and not the glyphicon/caret! if(!$(thisItem).is('a') && !$(thisItem).is('button')) { // Do it again on the parent keepOpen(thisItem.parentElement) return; } // Onlick so it works for the dynamic items! $(thisItem).siblings('.dropdown-menu').children().click(function(e) { // Not for links if(!$(e.target).is('a')) { e.stopPropagation(); } }); // Add possible tooltips and make sure they get removed if(!isMobile) { $(thisItem).siblings('.dropdown-menu').children('[data-tooltip="true"]').tooltip({ trigger: 'hover', container: 'body' }) $(thisItem).parent().on('hide.bs.dropdown', function() { $(thisItem).siblings('.dropdown-menu').children('[data-tooltip="true"]').tooltip('hide') }) } } // Show history details function showDetails(thisItem) { // Unfortunatly the .dropdown('toggle') doesn't work in this setup, so work-a-round // Open the details of this, or close it? if($(thisItem).parent().find('.delete>.dropdown').hasClass('open')) { // One click = close $(thisItem).parent().find('.delete>.dropdown>a').click() } else { // Needs timeout, otherwise it thinks its the 'close' click for some reason setTimeout(function() { $(thisItem).parent().find('.delete>.dropdown>a').click() },1) } } // Check all functionality function checkAllFiles(objCheck, onlyCheck) { // Get which ones we care about var allChecks = $($(objCheck).data('checkrange')).filter(':not(:disabled):visible'); // We need to re-evaltuate the state of this check-all // Otherwise the 'inderterminate' will be overwritten by the click event! setCheckAllState('#'+objCheck.id, $(objCheck).data('checkrange')) // Now we can check what happend if(objCheck.indeterminate) { // Uncheck if we don't need trigger if(onlyCheck) { allChecks.filter(":checked").prop('checked', false) } else { allChecks.filter(":checked").trigger("click") } } else { // Toggle their state by a click allChecks.trigger("click") } } // To update the check-all button nicely function setCheckAllState(checkSelector, rangeSelector) { // See how many are checked var allChecks = $(rangeSelector).filter(':not(:disabled):visible') var nrChecks = allChecks.filter(":checked"); if(nrChecks.length === 0) { $(checkSelector).prop({'checked': false, 'indeterminate': false}) } else if(nrChecks.length == allChecks.length) { $(checkSelector).prop({'checked': true, 'indeterminate': false}) } else { $(checkSelector).prop({'checked': false, 'indeterminate': true}) } } // Shift-range functionality for checkboxes function checkShiftRange(strCheckboxes) { // Get them all var arrAllChecks = $(strCheckboxes); // Get index of the first and last var startCheck = arrAllChecks.index($(strCheckboxes + ':checked:first')); var endCheck = arrAllChecks.index($(strCheckboxes + ':checked:last')); // Everything in between click it to trigger addMultiEdit arrAllChecks.slice(startCheck, endCheck).filter(':not(:checked)').trigger('click') } // Hide completed files in files-modal function hideCompletedFiles() { if($('#filelist-showcompleted').hasClass('hover-button')) { // Hide all $('.item-files-table tr.files-done').hide(); $('#filelist-showcompleted').removeClass('hover-button') // Set storage localStorageSetItem('showCompletedFiles', 'No') } else { // show all $('.item-files-table tr.files-done').show(); $('#filelist-showcompleted').addClass('hover-button') // Set storage localStorageSetItem('showCompletedFiles', 'Yes') } } // Show status modal and switch to orphaned jobs tab function showOrphans() { $('a[href="#modal-options"]').click().parent().click(); $('a[href="#options-orphans"]').click() } // Show notification function showNotification(notiName, notiTimeout, fileCounter) { // Set uploadcounter if there is one $('.main-notification-box .main-notification-box-file-count').text(fileCounter) // Hide others, show the new one $('.main-notification-box>div').hide() $(notiName).css('display', 'inline') // Only fade in when hidden $('.main-notification-box:hidden').fadeIn() // Remove after timeout if(notiTimeout) { setTimeout(function() { hideNotification(true); }, notiTimeout) } } // Hide notification function hideNotification(fadeItOut) { // Hide the box with or without effect if(fadeItOut) { $('.main-notification-box').fadeOut() } else { $('.main-notification-box').hide() } }SABnzbd-2.3.2/interfaces/Glitter/templates/static/javascripts/glitter.filelist.pagination.js0000644000000000000000000003337313217005257030467 0ustar 00000000000000// For the file-list function Fileslisting(parent) { var self = this; self.parent = parent; self.fileItems = ko.observableArray([]); // Need to reserve these names to be overwritten self.filelist_name = ko.observable(); self.filelist_password = ko.observable(); // Load the function and reset everything self.loadFiles = function(queue_item) { // Update self.currentItem = queue_item; self.fileItems.removeAll() self.triggerUpdate() // Update name/password self.filelist_name(self.currentItem.name()) self.filelist_password(self.currentItem.password()) // Hide ok button and reset $('#modal-item-filelist .glyphicon-floppy-saved').hide() $('#modal-item-filelist .glyphicon-lock').show() // Set state of the check-all setCheckAllState('#modal-item-files .multioperations-selector input[type="checkbox"]', '#modal-item-files .files-sortable input') // Show $('#modal-item-files').modal('show'); // Stop updating on closing of the modal $('#modal-item-files').on('hidden.bs.modal', function() { self.removeUpdate(); }) } // Move to top and bottom buttons self.moveButton = function (item,event) { var targetRow, sourceRow, tbody; sourceRow = $(event.currentTarget).parents("tr").filter(":first"); tbody = sourceRow.parents("tbody").filter(":first"); ko.utils.domData.set(sourceRow[0], "ko_sourceIndex", ko.utils.arrayIndexOf(sourceRow.parent().children(), sourceRow[0])); sourceRow = sourceRow.detach(); if ($(event.currentTarget).is(".buttonMoveToTop")) { // we are moving to the top targetRow = tbody.children(".files-done").filter(":last"); } else { //we are moving to the bottom targetRow = tbody.children(".files-sortable").filter(":last"); } if(targetRow.length < 1 ){ // we found an edge case and need to do something special targetRow = tbody.children(".files-sortable").filter(":first"); sourceRow.insertBefore(targetRow[0]); } else { sourceRow.insertAfter($(targetRow[0])); } tbody.sortable('option', 'update').call(tbody[0],null, { item: sourceRow }); }; // Trigger update self.triggerUpdate = function() { // Call API callAPI({ mode: 'get_files', value: self.currentItem.id, limit: 5 }).then(function(response) { // When there's no files left we close the modal and the update will be stopped // For example when the job has finished downloading if(response.files.length === 0) { $('#modal-item-files').modal('hide'); return; } // Go over them all var newItems = []; $.each(response.files, function(index, slot) { // Existing or updating? var existingItem = ko.utils.arrayFirst(self.fileItems(), function(i) { return i.nzf_id() == slot.nzf_id; }); if(existingItem) { // Update the rest existingItem.updateFromData(slot); } else { // Add files item newItems.push(new FileslistingModel(self, slot)); } }) // Add new ones in 1 time instead of every single push if(newItems.length > 0) { ko.utils.arrayPushAll(self.fileItems, newItems); self.fileItems.valueHasMutated(); } // Check if we show/hide completed if(localStorageGetItem('showCompletedFiles') == 'No') { $('.item-files-table tr.files-done').hide(); $('#filelist-showcompleted').removeClass('hover-button') } // Refresh with same as rest self.setUpdate() }) } // Set update self.setUpdate = function() { self.updateTimeout = setTimeout(function() { self.triggerUpdate() }, parent.refreshRate() * 1000) } // Remove the update self.removeUpdate = function() { clearTimeout(self.updateTimeout) } // Move in sortable self.move = function(event) { // How much did we move? var nrMoves = event.sourceIndex - event.targetIndex; var direction = (nrMoves > 0 ? 'Up' : 'Down') // We have to create the data-structure before, to be able to use the name as a key var dataToSend = {}; dataToSend[event.item.nzf_id()] = 'on'; dataToSend['session'] = apiKey; dataToSend['action_key'] = direction; dataToSend['action_size'] = Math.abs(nrMoves); // Activate with this weird URL "API" callSpecialAPI("./nzb/" + self.currentItem.id + "/bulk_operation/", dataToSend) }; // Remove selected files self.removeSelectedFiles = function() { // We have to create the data-structure before, to be able to use the name as a key var dataToSend = {}; dataToSend['session'] = apiKey; dataToSend['action_key'] = 'Delete'; // Get all selected ones $('.item-files-table input:checked:not(:disabled)').each(function() { // Add this item dataToSend[$(this).prop('name')] = 'on'; }) // Activate with this weird URL "API" callSpecialAPI("./nzb/" + self.currentItem.id + "/bulk_operation/", dataToSend).then(function() { // Fade it out $('.item-files-table input:checked:not(:disabled)').parents('tr').fadeOut(fadeOnDeleteDuration, function() { // Set state of the check-all setCheckAllState('#modal-item-files .multioperations-selector input[type="checkbox"]', '#modal-item-files .files-sortable input') }) }) } // For changing the passwords self.setNzbPassword = function() { // Have to also send the current name for it to work callAPI({ mode: 'queue', name: 'rename', value: self.currentItem.id, value2: self.currentItem.name(), value3: $('#nzb_password').val() }).then(function() { // Refresh, reset and close parent.refresh() $('#modal-item-filelist .glyphicon-floppy-saved').show() $('#modal-item-filelist .glyphicon-lock').hide() $('#modal-item-files').modal('hide') }) return false; } // Check all self.checkAllFiles = function(item, event) { // Get which ones we care about var allChecks = $('#modal-item-files .files-sortable input').filter(':not(:disabled):visible'); // We need to re-evaltuate the state of this check-all // Otherwise the 'inderterminate' will be overwritten by the click event! setCheckAllState('#modal-item-files .multioperations-selector input[type="checkbox"]', '#modal-item-files .files-sortable input') // Now we can check what happend if(event.target.indeterminate) { allChecks.filter(":checked").prop('checked', false) } else { // Toggle their state by a click allChecks.prop('checked', !event.target.checked) event.target.checked = !event.target.checked; event.target.indeterminate = false; } // Set state of all the check-all's setCheckAllState('#modal-item-files .multioperations-selector input[type="checkbox"]', '#modal-item-files .files-sortable input') return true; } // For selecting range and the check-all button self.checkSelectRange = function(data, event) { if(event.shiftKey) { checkShiftRange('#modal-item-files .files-sortable input:not(:disabled)') } // Set state of the check-all setCheckAllState('#modal-item-files .multioperations-selector input[type="checkbox"]', '#modal-item-files .files-sortable input') return true; } } // Indiviual file models function FileslistingModel(parent, data) { var self = this; // Define veriables self.filename = ko.observable(data.filename); self.nzf_id = ko.observable(data.nzf_id); self.file_age = ko.observable(data.age); self.mb = ko.observable(data.mb); self.canselect = ko.observable(data.status != "finished" && data.status != "queued"); self.isdone = ko.observable(data.status == "finished"); self.percentage = ko.observable(self.isdone() ? fixPercentages(100) : fixPercentages((100 - (data.mbleft / data.mb * 100)).toFixed(0))); // Update internally self.updateFromData = function(data) { self.filename(data.filename) self.nzf_id(data.nzf_id) self.file_age(data.age) self.mb(data.mb) self.canselect(data.status != "finished" && data.status != "queued") self.isdone(data.status == "finished") // Data is given in MB, would always show 0% for small files even if completed self.percentage(self.isdone() ? fixPercentages(100) : fixPercentages((100 - (data.mbleft / data.mb * 100)).toFixed(0))) } } // Model for pagination, since we use it multiple times function paginationModel(parent) { var self = this; // Var's self.nrPages = ko.observable(0); self.currentPage = ko.observable(1); self.currentStart = ko.observable(0); self.allpages = ko.observableArray([]).extend({ rateLimit: 50 }); // Has pagination self.hasPagination = ko.pureComputed(function() { return self.nrPages() > 1; }) // Subscribe to number of items parent.totalItems.subscribe(function() { // Update self.updatePages(); }) // Subscribe to changes of pagination limit parent.paginationLimit.subscribe(function(newValue) { self.updatePages(); self.moveToPage(self.currentPage()); }) // Easy handler for adding a page-link self.addPaginationPageLink = function(pageNr) { // Return object for adding return { page: pageNr, isCurrent: pageNr == self.currentPage(), isDots: false, onclick: function(data) { self.moveToPage(data.page); } } } // Easy handler to add dots self.addDots = function() { return { page: '...', isCurrent: false, isDots: true, onclick: function() {} } } self.updatePages = function() { // Empty it self.allpages.removeAll(); // How many pages do we need? if(parent.totalItems() <= parent.paginationLimit()) { // Empty it self.nrPages(1) self.currentStart(0); // Are we on next page? if(self.currentPage() > 1) { // Force full update parent.parent.refresh(true); } // Move to current page self.currentPage(1); // Force full update parent.parent.refresh(true); } else { // Calculate number of pages needed var newNrPages = Math.ceil(parent.totalItems() / parent.paginationLimit()) // Make sure the current page still exists if(self.currentPage() > newNrPages) { self.moveToPage(newNrPages); return; } // All the cases if(newNrPages > 7) { // Do we show the first ones if(self.currentPage() < 5) { // Just add the first 4 $.each(new Array(5), function(index) { self.allpages.push(self.addPaginationPageLink(index + 1)) }) // Dots self.allpages.push(self.addDots()) // Last one self.allpages.push(self.addPaginationPageLink(newNrPages)) } else { // Always add the first self.allpages.push(self.addPaginationPageLink(1)) // Dots self.allpages.push(self.addDots()) // Are we near the end? if((newNrPages - self.currentPage()) < 4) { // We add the last ones $.each(new Array(5), function(index) { self.allpages.push(self.addPaginationPageLink((index - 4) + (newNrPages))) }) } else { // We are in the center so display the center 3 $.each(new Array(3), function(index) { self.allpages.push(self.addPaginationPageLink(self.currentPage() + (index - 1))) }) // Dots self.allpages.push(self.addDots()) // Last one self.allpages.push(self.addPaginationPageLink(newNrPages)) } } } else { // Just add them $.each(new Array(newNrPages), function(index) { self.allpages.push(self.addPaginationPageLink(index + 1)) }) } // Change of number of pages? if(newNrPages != self.nrPages()) { // Update self.nrPages(newNrPages); } } } // Update on click self.moveToPage = function(page) { // Update page and start self.currentPage(page) self.currentStart((page - 1) * parent.paginationLimit()) // Re-paginate self.updatePages(); // Force full update parent.parent.refresh(true); } }SABnzbd-2.3.2/interfaces/Glitter/templates/static/javascripts/glitter.history.js0000644000000000000000000004415613217005257026226 0ustar 00000000000000/** Model for the whole History with all its items **/ function HistoryListModel(parent) { var self = this; self.parent = parent; // Variables self.lastUpdate = 0; self.historyItems = ko.observableArray([]) self.showFailed = ko.observable(false); self.isLoading = ko.observable(false).extend({ rateLimit: 100 }); self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } }); self.paginationLimit = ko.observable(10).extend({ persist: 'historyPaginationLimit' }); self.totalItems = ko.observable(0); self.pagination = new paginationModel(self); // Download history info self.downloadedToday = ko.observable(); self.downloadedWeek = ko.observable(); self.downloadedMonth = ko.observable(); self.downloadedTotal = ko.observable(); // Update function for history list self.updateFromData = function(data) { /*** See if there's anything to update ***/ if(!data) return; self.lastUpdate = data.last_history_update /*** History list functions per item ***/ var itemIds = $.map(self.historyItems(), function(i) { return i.historyStatus.nzo_id(); }); // For new items var newItems = []; $.each(data.slots, function(index, slot) { var existingItem = ko.utils.arrayFirst(self.historyItems(), function(i) { return i.historyStatus.nzo_id() == slot.nzo_id; }); // Set index in the results slot.index = index // Update or add? if(existingItem) { existingItem.updateFromData(slot); itemIds.splice(itemIds.indexOf(slot.nzo_id), 1); } else { // Add history item newItems.push(new HistoryModel(self, slot)); } }); // Remove all items if(itemIds.length == self.paginationLimit()) { // Replace it, so only 1 Knockout DOM-update! self.historyItems(newItems); newItems = []; } else { // Remove the un-used ones $.each(itemIds, function() { var id = this.toString(); self.historyItems.remove(ko.utils.arrayFirst(self.historyItems(), function(i) { return i.historyStatus.nzo_id() == id; })); }); } // Add new ones if(newItems.length > 0) { ko.utils.arrayPushAll(self.historyItems, newItems); self.historyItems.valueHasMutated(); // We also check if it might be in the Multi-edit if(self.parent.queue.multiEditItems().length > 0) { $.each(newItems, function() { var currentItem = this; self.parent.queue.multiEditItems.remove(function(inList) { return inList.id == currentItem.nzo_id; }) }) } } // Sort every time (takes just few msec) self.historyItems.sort(function(a, b) { return a.index < b.index ? -1 : 1; }); /*** History information ***/ self.totalItems(data.noofslots); self.downloadedToday(data.day_size); self.downloadedWeek(data.week_size); self.downloadedMonth(data.month_size); self.downloadedTotal(data.total_size); }; // Save pagination state self.paginationLimit.subscribe(function(newValue) { // Save in config if global config if(self.parent.useGlobalOptions()) { callAPI({ mode: "set_config", section: "misc", keyword: "history_limit", value: newValue }) } }); // Retry a job self.retryJob = function(form) { // Adding a extra retry file happens through this special function var data = new FormData(); data.append("nzbfile", $(form.nzbFile)[0].files[0]); data.append("job", $('#modal-retry-job input[name="retry_job_id"]').val()); data.append("password", $('#retry_job_password').val()); data.append("session", apiKey); // Add $.ajax({ url: "./retry_pp", type: "POST", cache: false, processData: false, contentType: false, data: data }).then(function() { self.parent.refresh(true) }); $("#modal-retry-job").modal("hide"); $('.btn-file em').html(glitterTranslate.chooseFile + '…') form.reset() } // Searching in history (rate-limited in decleration) self.searchTerm.subscribe(function() { // Make sure we refresh self.lastUpdate = 0 self.parent.refresh(); // Go back to page 1 if(self.pagination.currentPage() != 1) { self.pagination.moveToPage(1); } }) // Clear searchterm self.clearSearchTerm = function(data, event) { // Was it escape key or click? if(event.type == 'mousedown' || (event.keyCode && event.keyCode == 27)) { // Set the loader so it doesn't flicker and then switch self.isLoading(true) self.searchTerm(''); self.parent.refresh() } // Was it click and the field is empty? Then we focus on the field if(event.type == 'mousedown' && self.searchTerm() == '') { $(event.target).parents('.search-box').find('input[type="text"]').focus() return; } // Need to return true to allow typing return true; } // Toggle showing failed self.toggleShowFailed = function(data, event) { // Set the loader so it doesn't flicker and then switch self.isLoading(true) self.showFailed(!self.showFailed()) // Forde hide tooltip so it doesn't linger $('#history-options a').tooltip('hide') // Force refresh self.parent.refresh(true) } // Retry all failed self.retryAllFailed = function(data, event) { // Ask to be sure if(confirm(glitterTranslate.retryAll)) { // Send the command callAPI({ mode: 'retry_all' }).then(function() { // Force refresh self.parent.refresh(true) }) } } // Empty history options self.emptyHistory = function(data, event) { // Make sure no flickering self.isLoading(true) // What event? var whatToRemove = $(event.target).data('action'); var del_files, value; // Purge failed if(whatToRemove == 'history-purge-failed') { del_files = 0; value = 'failed'; } // Also remove files if(whatToRemove == 'history-purgeremove-failed') { del_files = 1; value = 'failed'; } // Remove completed if(whatToRemove == 'history-purge-completed') { del_files = 0; value = 'completed'; } // Remove the ones on this page if(whatToRemove == 'history-purge-page') { // List all the ID's var strIDs = ''; $.each(self.historyItems(), function(index) { // Only append when it's a download that can be deleted if(!this.processingDownload() && !this.processingWaiting()) { strIDs = strIDs + this.nzo_id + ','; } }) // Send the command callAPI({ mode: 'history', name: 'delete', del_files: 1, value: strIDs }).then(function() { // Clear search, refresh and hide self.searchTerm(''); self.parent.refresh(); $("#modal-purge-history").modal('hide'); }) return; } // Call API and close the window callAPI({ mode: 'history', name: 'delete', value: value, del_files: del_files }).then(function() { self.parent.refresh(); $("#modal-purge-history").modal('hide'); }); }; } /** Model for each History item **/ function HistoryModel(parent, data) { var self = this; self.parent = parent; // We only update the whole set of information on first add // If we update the full set every time it uses lot of CPU // The Status/Actionline/scriptline/completed we do update every time // When clicked on the more-info button we load the rest again self.nzo_id = data.nzo_id; self.index = data.index; self.updateAllHistory = false; self.hasDropdown = ko.observable(false); self.historyStatus = ko.mapping.fromJS(data); self.status = ko.observable(data.status); self.action_line = ko.observable(data.action_line); self.script_line = ko.observable(data.script_line); self.fail_message = ko.observable(data.fail_message); self.completed = ko.observable(data.completed); self.canRetry = ko.observable(data.retry); // Update function self.updateFromData = function(data) { // Fill all the basic info self.index = data.index self.status(data.status) self.action_line(data.action_line) self.script_line(data.script_line) self.fail_message(data.fail_message) self.completed(data.completed) self.canRetry(data.retry) // Update all ONCE? if(self.updateAllHistory) { ko.mapping.fromJS(data, {}, self.historyStatus); self.updateAllHistory = false; } }; // True/false if failed or not self.failed = ko.pureComputed(function() { return self.status() === 'Failed'; }); // Waiting? self.processingWaiting = ko.pureComputed(function() { return(self.status() == 'Queued') }) // Processing or done? self.processingDownload = ko.pureComputed(function() { var status = self.status(); // When we can cancel if (status === 'Extracting' || status === 'Verifying' || status == 'Repairing' || status === 'Running') { return 2 } // These cannot be cancelled if(status === 'Moving') { return 1 } return false; }) // Format status text self.statusText = ko.pureComputed(function() { if(self.action_line() !== '') return self.action_line(); if(self.status() === 'Failed') // Failed return self.fail_message(); if(self.status() === 'Queued') return glitterTranslate.status['Queued']; if(self.script_line() === '') // No script line return glitterTranslate.status['Completed'] return self.script_line(); }); // Extra history column self.extraText = ko.pureComputed(function() { // Picked anything? switch(self.parent.parent.extraHistoryColumn()) { case 'speed': // Anything to calculate? if(self.historyStatus.bytes() > 0 && self.historyStatus.download_time() > 0) { try { // Extract the Download section var downloadLog = ko.utils.arrayFirst(self.historyStatus.stage_log(), function(item) { return item.name() == 'Download' }); // Extract the speed return downloadLog.actions()[0].match(/(\S*\s\S+)(?=)/)[0] } catch(err) { } } return; case 'category': // Exception for * if(self.historyStatus.category() == "*") return glitterTranslate.defaultText return self.historyStatus.category(); case 'size': return self.historyStatus.size(); } return; }) // Format completion time self.completedOn = ko.pureComputed(function() { return displayDateTime(self.completed(), parent.parent.dateFormat(), 'X') }); // Subscribe to retryEvent so we can load the password self.canRetry.subscribe(function() { self.updateAllHistory = true; }) // Re-try button self.retry = function() { // Set JOB-id $('#modal-retry-job input[name="retry_job_id"]').val(self.nzo_id) // Set password $('#retry_job_password').val(self.historyStatus.password()) // Open modal $('#modal-retry-job').modal("show") }; // Update information only on click self.updateAllHistoryInfo = function(data, event) { // Show self.hasDropdown(true); // Update all info self.updateAllHistory = true; parent.parent.refresh(true); // Try to keep open keepOpen(event.target) } // Use KO-afterRender to add the click-functionality always self.addHistoryStatusStuff = function(item) { $(item).find('.history-status-modallink a').click(function(e) { // Modal or 'More' click? if($(this).is('.history-status-dmca')) { // Pass return true; } else if($(this).is('.history-status-more')) { // Expand the rest of the text and hide the button $(this).siblings('.history-status-hidden').slideDown() $(this).hide() } else { // Info in modal $('#history-script-log .modal-body').load($(this).attr('href'), function(result) { // Set title and then remove it $('#history-script-log .modal-title').text($(this).find("h3").text()) $(this).find("h3, title").remove() $('#history-script-log').modal('show'); }); } return false; }) } // Delete button self.deleteSlot = function(item, event) { // Confirm? if(!self.parent.parent.confirmDeleteHistory() || confirm(glitterTranslate.removeDow1)) { // Are we still processing and it can be stopped? if(item.processingDownload() == 2) { callAPI({ mode: 'cancel_pp', value: self.nzo_id }) // All we can do is wait } else { // Delete the item callAPI({ mode: 'history', name: 'delete', del_files: 1, value: self.nzo_id }).then(function(response) { if(response.status) { // Fade and remove $(event.currentTarget).parent().parent().fadeOut(fadeOnDeleteDuration, function() { // Make sure no flickering (if there are more items left) and then remove self.parent.isLoading(self.parent.totalItems() > 1) self.parent.historyItems.remove(self); self.parent.parent.refresh(); }) } }); } } }; // User voting self.setUserVote = function(item, event) { // Send vote callAPI({ mode: 'queue', name: 'rating', type: 'vote', setting: $(event.target).val(), value: self.nzo_id }).then(function(response) { // Update all info self.updateAllHistory = true; self.parent.parent.refresh(true) }) } // User rating self.setUserRating = function(item, event) { // Audio or video var changeWhat = 'audio'; if($(event.target).attr('name') == 'ratings-video') { changeWhat = 'video'; } // Only on user-event, not the auto-fired ones if(!event.originalEvent) return; // Send vote callAPI({ mode: 'queue', name: 'rating', type: changeWhat, setting: $(event.target).val(), value: self.nzo_id }).then(function(response) { // Update all info self.updateAllHistory = true; self.parent.parent.refresh(true) }) } // User comment self.setUserReport = function(form) { // What are we reporting? var userReport = $(form).find('input[name="rating_flag"]:checked').val(); var userDetail = ''; // Anything selected? if(!userReport) { alert(glitterTranslate.noSelect) return; } // Extra info? if(userReport == 'comment') userDetail = $(form).find('input[name="ratings-report-comment"]').val(); if(userReport == 'other') userDetail = $(form).find('input[name="ratings-report-other"]').val(); // Exception for servers if(userReport == 'expired') { // Which server? userDetail = $(form).find('select[name="ratings-report-expired-server"]').val(); // All? if(userDetail == "") { // Loop over all servers $.each(parent.parent.servers, function(index, server) { // Set timeout because simultanious requests don't work (yet) setTimeout(function() { submitUserReport(server.name) }, index * 1500) }) } else { // Just the one server submitUserReport(userDetail) } } else { submitUserReport(userDetail) } // After all, close it form.reset(); $(form).parent().parent().dropdown('toggle'); alert(glitterTranslate.sendThanks) function submitUserReport(theDetail) { // Send note callAPI({ mode: 'queue', name: 'rating', type: 'flag', setting: userReport, detail: theDetail, value: self.nzo_id }) } return false } }SABnzbd-2.3.2/interfaces/Glitter/templates/static/javascripts/glitter.js0000644000000000000000000000367413217005257024526 0ustar 00000000000000/****** Glitter V1 By Safihre (2015) - safihre@sabnzbd.org Code extended from Shiny-template Code examples used from Knockstrap-template The setup is hierarchical, 1 main ViewModel that contains: - ViewModel - QueueListModel - paginationModel - QueueModel (item 1) - QueueModel (item 2) - ... - QueueModel (item n+1) - HistoryListModel - paginationModel - HistoryModel (item 1) - HistoryModel (item 2) - ... - HistoryModel (item n+1) - Fileslisting - FileslistingModel (file 1) - FileslistingModel (file 2) - ... - FileslistingModel (file n+1) ViewModel also contains all the code executed on document ready and functions responsible for the status information, adding NZB, etc. The QueueModel/HistoryModel's get added to the list-models when jobs are added or on switching of pages (using paginationModel). Once added only the properties that changed during a refresh get updated. In the history all the detailed information is only updated when created and when the user clicks on a detail. The Fileslisting is only populated and updated when it is opened for one of the QueueModel's. ******/ #include raw $webdir + "/static/javascripts/glitter.basic.js"# /** GLITTER CODE **/ \$(function() { 'use strict'; #include raw $webdir + "/static/javascripts/glitter.main.js"# #include raw $webdir + "/static/javascripts/glitter.queue.js"# #include raw $webdir + "/static/javascripts/glitter.history.js"# #include raw $webdir + "/static/javascripts/glitter.filelist.pagination.js"# // GO!!! ko.applyBindings(new ViewModel(), document.getElementById("sabnzbd")); });SABnzbd-2.3.2/interfaces/Glitter/templates/static/javascripts/glitter.main.js0000644000000000000000000012600713217005257025445 0ustar 00000000000000/** Define main view model **/ function ViewModel() { // Initialize models var self = this; self.queue = new QueueListModel(this); self.history = new HistoryListModel(this); self.filelist = new Fileslisting(this); // Set status varibales self.isRestarting = ko.observable(false); self.useGlobalOptions = ko.observable(true).extend({ persist: 'useGlobalOptions' }); self.refreshRate = ko.observable(1).extend({ persist: 'pageRefreshRate' }); self.dateFormat = ko.observable('fromNow').extend({ persist: 'pageDateFormat' }); self.displayTabbed = ko.observable().extend({ persist: 'displayTabbed' }); self.displayCompact = ko.observable(false).extend({ persist: 'displayCompact' }); self.confirmDeleteQueue = ko.observable(true).extend({ persist: 'confirmDeleteQueue' }); self.confirmDeleteHistory = ko.observable(true).extend({ persist: 'confirmDeleteHistory' }); self.extraQueueColumn = ko.observable('').extend({ persist: 'extraColumn' }); self.extraHistoryColumn = ko.observable('').extend({ persist: 'extraHistoryColumn' }); self.showActiveConnections = ko.observable(false).extend({ persist: 'showActiveConnections' }); self.speedMetrics = { K: "KB/s", M: "MB/s", G: "GB/s" }; // Set information varibales self.title = ko.observable(); self.speed = ko.observable(0); self.speedMetric = ko.observable(); self.bandwithLimit = ko.observable(false); self.pauseCustom = ko.observable('').extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } }); self.speedLimit = ko.observable(100).extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } }); self.speedLimitInt = ko.observable(false); // We need the 'internal' counter so we don't trigger the API all the time self.downloadsPaused = ko.observable(false); self.timeLeft = ko.observable("0:00"); self.diskSpaceLeft1 = ko.observable(); self.diskSpaceLeft2 = ko.observable(); self.queueDataLeft = ko.observable(); self.diskSpaceExceeded1 = ko.observable(false); self.diskSpaceExceeded2 = ko.observable(false); self.quotaLimit = ko.observable(); self.quotaLimitLeft = ko.observable(); self.systemLoad = ko.observable(); self.cacheSize = ko.observable(); self.cacheArticles = ko.observable(); self.nrWarnings = ko.observable(0); self.allWarnings = ko.observableArray([]); self.allMessages = ko.observableArray([]); self.onQueueFinish = ko.observable(''); self.speedHistory = []; // Statusinfo container self.hasStatusInfo = ko.observable(false); self.hasPerformanceInfo = ko.observable(false); self.statusInfo = {}; self.statusInfo.folders = ko.observableArray([]); self.statusInfo.servers = ko.observableArray([]); self.statusInfo.localipv4 = ko.observable(); self.statusInfo.publicipv4 = ko.observable(); self.statusInfo.ipv6 = ko.observable(); self.statusInfo.dnslookup = ko.observable(); self.statusInfo.pystone = ko.observable(); self.statusInfo.cpumodel = ko.observable(); self.statusInfo.loglevel = ko.observable(); self.statusInfo.downloaddir = ko.observable(); self.statusInfo.downloaddirspeed = ko.observable(); self.statusInfo.completedir = ko.observable(); self.statusInfo.completedirspeed = ko.observable(); /*** Dynamic functions ***/ // Make the speedlimit tekst self.speedLimitText = ko.pureComputed(function() { // Set? if(!self.bandwithLimit()) return; // The text var bandwithLimitText = self.bandwithLimit().replace(/[^a-zA-Z]+/g, ''); // Only the number var speedLimitNumberFull = (parseFloat(self.bandwithLimit()) * (self.speedLimit() / 100)); // Trick to only get decimal-point when needed var speedLimitNumber = Math.round(speedLimitNumberFull*10)/10; // Fix it for lower than 1MB/s if(bandwithLimitText == 'M' && speedLimitNumber < 1) { bandwithLimitText = 'K'; speedLimitNumber = Math.round(speedLimitNumberFull * 1024); } // Show text return self.speedLimit() + '% (' + speedLimitNumber + ' ' + self.speedMetrics[bandwithLimitText] + ')'; }); // Dynamic speed text function self.speedText = ko.pureComputed(function() { return self.speed() + ' ' + (self.speedMetrics[self.speedMetric()] ? self.speedMetrics[self.speedMetric()] : "KB/s"); }); // Dynamic icon self.SABIcon = ko.pureComputed(function() { if(self.downloadsPaused()) { return './staticcfg/ico/faviconpaused.ico?v=1.1.0'; } else { return './staticcfg/ico/favicon.ico?v=1.1.0'; } }) // Dynamic queue length check self.hasQueue = ko.pureComputed(function() { return(self.queue.queueItems().length > 0 || self.queue.searchTerm() || self.queue.isLoading()) }) // Dynamic history length check self.hasHistory = ko.pureComputed(function() { // We also 'have history' if we can't find any results of the search or there are no failed ones return (self.history.historyItems().length > 0 || self.history.searchTerm() || self.history.showFailed() || self.history.isLoading()) }) self.hasWarnings = ko.pureComputed(function() { return(self.allWarnings().length > 0) }) // Check for any warnings/messages self.hasMessages = ko.pureComputed(function() { return parseInt(self.nrWarnings()) + self.allMessages().length; }) // Update main queue self.updateQueue = function(response) { // Block in case off dragging if(!self.queue.shouldUpdate()) return; // Make sure we are displaying the interface if(self.isRestarting() >= 1) { // Decrease the counter by 1 // In case of restart (which takes time to fire) we count down // In case of re-connect after failure it counts from 1 so emmediate continuation self.isRestarting(self.isRestarting() - 1); return; } /*** Possible login failure? ***/ if(response.hasOwnProperty('error') && response.error == 'Missing authentication') { // Restart document.location = document.location; } /*** Basic information ***/ // Queue left self.queueDataLeft(response.queue.mbleft > 0 ? response.queue.sizeleft : '') // Paused? self.downloadsPaused(response.queue.paused); // Finish action. Replace null with empty self.onQueueFinish(response.queue.finishaction ? response.queue.finishaction : ''); // Disk sizes self.diskSpaceLeft1(response.queue.diskspace1_norm) // Same sizes? Then it's all 1 disk! if(response.queue.diskspace1 != response.queue.diskspace2) { self.diskSpaceLeft2(response.queue.diskspace2_norm) } else { self.diskSpaceLeft2('') } // Did we exceed the space? self.diskSpaceExceeded1(parseInt(response.queue.mbleft)/1024 > parseFloat(response.queue.diskspace1)) self.diskSpaceExceeded2(parseInt(response.queue.mbleft)/1024 > parseFloat(response.queue.diskspace2)) // Quota self.quotaLimit(response.queue.quota) self.quotaLimitLeft(response.queue.left_quota) // System load self.systemLoad(response.queue.loadavg) // Cache self.cacheSize(response.queue.cache_size) self.cacheArticles(response.queue.cache_art) // Warnings (new warnings will trigger an update of allMessages) self.nrWarnings(response.queue.have_warnings) /*** Spark line ***/ // Break the speed if empty queue if(response.queue.sizeleft == '0 B') { response.queue.kbpersec = 0; response.queue.speed = '0'; } // Re-format the speed var speedSplit = response.queue.speed.split(/\s/); self.speed(parseFloat(speedSplit[0])); self.speedMetric(speedSplit[1]); // Update sparkline data if(self.speedHistory.length >= 275) { // Remove first one self.speedHistory.shift(); } // Add self.speedHistory.push(parseInt(response.queue.kbpersec)); // Is sparkline visible? Not on small mobile devices.. if($('.sparkline-container').css('display') != 'none') { // Make sparkline if(self.speedHistory.length == 1) { // We only use speedhistory from SAB if we use global settings // Otherwise SAB doesn't know the refresh rate if(!self.useGlobalOptions()) { sabSpeedHistory = []; } else { // Update internally self.speedHistory = sabSpeedHistory; } // Create $('.sparkline').peity("line", { width: 275, height: 32, fill: '#9DDB72', stroke: '#AAFFAA', values: sabSpeedHistory }) } else { // Update $('.sparkline').text(self.speedHistory.join(",")).change() } } /*** Speedlimit ***/ // Nothing = 100% response.queue.speedlimit = (response.queue.speedlimit == '') ? 100.0 : parseFloat(response.queue.speedlimit).toFixed(1); // Trick to only get decimal-point when needed response.queue.speedlimit = Math.round(response.queue.speedlimit*10)/10; self.speedLimitInt(response.queue.speedlimit) // Only update from external source when user isn't doing input if(!$('.speedlimit-dropdown .btn-group .btn-group').is('.open')) { self.speedLimit(response.queue.speedlimit) } /*** Download timing and pausing ***/ var timeString = response.queue.timeleft; if(timeString === '') { timeString = '0:00'; } else { timeString = rewriteTime(response.queue.timeleft) } // Paused main queue if(self.downloadsPaused()) { if(response.queue.pause_int == '0') { timeString = glitterTranslate.paused; } else { var pauseSplit = response.queue.pause_int.split(/:/); var seconds = parseInt(pauseSplit[0]) * 60 + parseInt(pauseSplit[1]); var hours = Math.floor(seconds / 3600); var minutes = Math.floor((seconds -= hours * 3600) / 60); seconds -= minutes * 60; // Add leading zeros if(minutes < 10) minutes = '0' + minutes; if(seconds < 10) seconds = '0' + seconds; // Final formating timeString = glitterTranslate.paused + ' (' + rewriteTime(hours + ":" + minutes + ":" + seconds) + ')'; } // Add info about amount of download (if actually downloading) if(response.queue.noofslots > 0 && parseInt(self.queueDataLeft()) > 0) { self.title(timeString + ' - ' + self.queueDataLeft() + ' ' + glitterTranslate.left + ' - SABnzbd') } else { // Set title with pause information self.title(timeString + ' - SABnzbd') } } else if(response.queue.noofslots > 0 && parseInt(self.queueDataLeft()) > 0) { // Set title only if we are actually downloading something.. self.title(self.speedText() + ' - ' + self.queueDataLeft() + ' ' + glitterTranslate.left + ' - SABnzbd') } else { // Empty title self.title('SABnzbd') } // Save for timing box self.timeLeft(timeString); // Update queue rows self.queue.updateFromData(response.queue); } // Update history items self.updateHistory = function(response) { if(!response) return; self.history.updateFromData(response.history); } // Set new update timer self.setNextUpdate = function() { self.interval = setTimeout(self.refresh, parseInt(self.refreshRate()) * 1000); } // Refresh function self.refresh = function(forceFullHistory) { // Clear previous timeout to prevent double-calls clearTimeout(self.interval); /** Limited refresh **/ // Only update the title when page not visible if(!pageIsVisible) { // Request new title callSpecialAPI('./queue/', { limit: 1, start: 0 }).done(function(data) { // Split title & speed var dataSplit = data.split('|||'); // Maybe the result is actually the login page? if(dataSplit[0].substring(0, 11) === ' -1) // Force the next full update to be full self.history.lastUpdate = 0 }).always(self.setNextUpdate) // Do not continue! return; } /** Do first load with start-data Only works when the server knows the settings! **/ if(glitterPreLoadHistory && self.useGlobalOptions()) { self.updateQueue(glitterPreLoadQueue); self.updateHistory(glitterPreLoadHistory); glitterPreLoadQueue = undefined; glitterPreLoadHistory = undefined; self.setNextUpdate() return; } /** Full refresh **/ // Do requests for full information // Catch the fail to display message var queueApi = callAPI({ mode: "queue", search: self.queue.searchTerm(), start: self.queue.pagination.currentStart(), limit: parseInt(self.queue.paginationLimit()) }) .done(self.updateQueue) .fail(function(response) { // Catch the failure of authorization error if(response.status == 401) { // Stop refresh and reload clearInterval(self.interval) location.reload(); } // Show screen self.isRestarting(1) }).always(self.setNextUpdate); // Force full history update? if(forceFullHistory) { self.history.lastUpdate = 0 } // History callAPI({ mode: "history", search: self.history.searchTerm(), failed_only: self.history.showFailed()*1, start: self.history.pagination.currentStart(), limit: parseInt(self.history.paginationLimit()), last_history_update: self.history.lastUpdate }).done(self.updateHistory); // We are now done with any loading // But we wait a few ms so Knockout has time to update setTimeout(function() { self.queue.isLoading(false); self.history.isLoading(false); }, 100) // Return for .then() functionality return queueApi; }; // Set pause action on click of toggle self.pauseToggle = function() { callAPI({ mode: (self.downloadsPaused() ? "resume" : "pause") }).then(self.refresh); self.downloadsPaused(!self.downloadsPaused()); } // Set pause timer self.pauseTime = function(item, event) { callAPI({ mode: 'config', name: 'set_pause', value: $(event.currentTarget).data('time') }).then(self.refresh); self.downloadsPaused(true); }; // Open modal self.openCustomPauseTime = function() { // Was it loaded already? if(!Date.i18n) { jQuery.getScript('./static/javascripts/date.min.js').then(function() { // After loading we start again self.openCustomPauseTime() }) return; } // Show modal $('#modal_custom_pause').modal('show') // Focus on the input field $('#modal_custom_pause').on('shown.bs.modal', function () { $('#customPauseInput').focus() }) // Reset on modal close $('#modal_custom_pause').on('hide.bs.modal', function () { self.pauseCustom(''); }) } // Update on changes self.pauseCustom.subscribe(function(newValue) { // Is it plain numbers? if(newValue.match(/^\s*\d+\s*$/)) { // Treat it as a number of minutes newValue += "minutes"; } // At least 3 charaters if(newValue.length < 3) { $('#customPauseOutput').text('').data('time', 0) $('#modal_custom_pause .btn-default').addClass('disabled') return; } // Fix DateJS bug it has some strange problem with the current day-of-month + 1 // Removing the space makes DateJS work properly newValue = newValue.replace(/\s*h|\s*m|\s*d/g, function(match) { return match.trim() }); // Parse var pauseParsed = Date.parse(newValue); // Did we get it? if(pauseParsed) { // Is it just now? if(pauseParsed <= Date.parse('now')) { // Try again with the '+' in front, the parser doesn't get 100min pauseParsed = Date.parse('+' + newValue); } // Calculate difference in minutes and save var pauseDuration = Math.round((pauseParsed - Date.parse('now'))/1000/60); $('#customPauseOutput').html(' ' +glitterTranslate.pauseFor + ' ' + pauseDuration + ' ' + glitterTranslate.minutes) $('#customPauseOutput').data('time', pauseDuration) $('#modal_custom_pause .btn-default').removeClass('disabled') } else if(newValue) { // No.. $('#customPauseOutput').text(glitterTranslate.pausePromptFail) $('#modal_custom_pause .btn-default').addClass('disabled') } }) // Save custom pause self.saveCustomPause = function() { // Get duration var pauseDuration = $('#customPauseOutput').data('time'); // If in the future if(pauseDuration > 0) { callAPI({ mode: 'config', name: 'set_pause', value: pauseDuration }).then(function() { // Refresh and close the modal self.refresh() self.downloadsPaused(true); $('#modal_custom_pause').modal('hide') }); } } // Update the warnings self.nrWarnings.subscribe(function(newValue) { // Really any change? if(newValue == self.allWarnings().length) return; // Get all warnings callAPI({ mode: 'warnings' }).then(function(response) { // Reset it all self.allWarnings.removeAll(); if(response) { // Newest first response.warnings.reverse() // Go over all warnings and add $.each(response.warnings, function(index, warning) { // Reformat CSS label and date // Replaces spaces by non-breakable spaces and newlines with br's var warningData = { index: index, type: glitterTranslate.status[warning.type].slice(0, -1), text: convertHTMLtoText(warning.text).replace(/ /g, '\u00A0').replace(/(?:\r\n|\r|\n)/g, '
'), timestamp: warning.time, css: (warning.type == "ERROR" ? "danger" : warning.type == "WARNING" ? "warning" : "info"), clear: self.clearWarnings }; self.allWarnings.push(warningData) }) } }); }) // Clear warnings through this special URL.. self.clearWarnings = function() { // Activate callSpecialAPI("./status/clearwarnings/").done(self.refresh) } // Clear messages self.clearMessages = function(whatToRemove) { // Remove specifc type of messages self.allMessages.remove(function(item) { return item.index == whatToRemove }); // Now so we don't show again today localStorageSetItem(whatToRemove, Date.now()) } // Update on speed-limit change self.speedLimit.subscribe(function(newValue) { // Only on new load if(!self.speedLimitInt()) return; // Update if(self.speedLimitInt() != newValue) { callAPI({ mode: "config", name: "speedlimit", value: newValue }) } }); // Clear speedlimit self.clearSpeedLimit = function() { // Send call to override speedlimit callAPI({ mode: "config", name: "speedlimit", value: 100 }) self.speedLimitInt(100.0) self.speedLimit(100.0) } // Shutdown options self.setOnQueueFinish = function(model, event) { // Ignore updates before the page is done if(!self.hasStatusInfo()) return; // Something changes callAPI({ mode: 'queue', name: 'change_complete_action', value: $(event.target).val() }) // Top stop blinking while the API is calling self.onQueueFinish($(event.target).val()) } // Use global settings or device-specific? self.useGlobalOptions.subscribe(function(newValue) { // Reload in case of enabling global options if(newValue) document.location = document.location; }) // Update refreshrate self.refreshRate.subscribe(function(newValue) { // Refresh now self.refresh(); // Save in config if global-settings if(self.useGlobalOptions()) { callAPI({ mode: "set_config", section: "misc", keyword: "refresh_rate", value: newValue }) } }) /*** Add NZB's ***/ // Updating the label self.updateBrowseLabel = function(data, event) { // Get filename var fileName = $(event.target).val().replace(/\\/g, '/').replace(/.*\//, ''); // Set label if(fileName) $('.btn-file em').text(fileName) } // From the upload self.addNZBFromFileForm = function(form) { // Anything? if(!$(form.nzbFile)[0].files[0]) { $('.btn-file').attr('style', 'border-color: red !important') setTimeout(function() { $('.btn-file').css('border-color', '') }, 2000) return false; } // Upload self.addNZBFromFile($(form.nzbFile)[0].files); // Hide modal, upload will reset the form $("#modal-add-nzb").modal("hide"); } // From URL self.addNZBFromURL = function(form) { // Anything? if(!$(form.nzbURL).val()) { $(form.nzbURL).attr('style', 'border-color: red !important') setTimeout(function() { $(form.nzbURL).css('border-color', '') }, 2000) return false; } // Build request var theCall = { mode: "addurl", name: $(form.nzbURL).val(), nzbname: $('#nzbname').val(), script: $('#modal-add-nzb select[name="Post-processing"]').val(), priority: $('#modal-add-nzb select[name="Priority"]').val(), pp: $('#modal-add-nzb select[name="Processing"]').val() } // Optional, otherwise they get mis-labeled if left empty if($('#modal-add-nzb select[name="Category"]').val() != '*') theCall.cat = $('#modal-add-nzb select[name="Category"]').val() if($('#modal-add-nzb select[name="Processing"]').val()) theCall.pp = $('#modal-add-nzb select[name="Category"]').val() // Add callAPI(theCall).then(function(r) { // Hide and reset/refresh self.refresh() $("#modal-add-nzb").modal("hide"); form.reset() $('#nzbname').val('') }); } // From the upload or filedrop self.addNZBFromFile = function(files, fileindex) { // First file if(fileindex === undefined) { fileindex = 0 } var file = files[fileindex] fileindex++ // Check if it's maybe a folder, we can't handle those if(!file.type && file.size % 4096 == 0) return; // Add notification showNotification('.main-notification-box-uploading', 0, fileindex) // Adding a file happens through this special function var data = new FormData(); data.append("name", file); data.append("mode", "addfile"); data.append("nzbname", $('#nzbname').val()); data.append("script", $('#modal-add-nzb select[name="Post-processing"]').val()) data.append("priority", $('#modal-add-nzb select[name="Priority"]').val()) data.append("apikey", apiKey); // Optional, otherwise they get mis-labeled if left empty if($('#modal-add-nzb select[name="Category"]').val() != '*') data.append("cat", $('#modal-add-nzb select[name="Category"]').val()); if($('#modal-add-nzb select[name="Processing"]').val()) data.append("pp", $('#modal-add-nzb select[name="Processing"]').val()); // Add this one $.ajax({ url: "./tapi", type: "POST", cache: false, processData: false, contentType: false, data: data }).then(function(r) { // Are we done? if(fileindex < files.length) { // Do the next one self.addNZBFromFile(files, fileindex) } else { // Refresh self.refresh(); // Hide notification hideNotification('.main-notification-box-uploading') // Reset the form $('#modal-add-nzb form').trigger('reset'); $('#nzbname').val('') $('.btn-file em').html(glitterTranslate.chooseFile + '…') } }); } // Load status info self.loadStatusInfo = function(item, event) { // Full refresh? Only on click and for the status-screen var statusFullRefresh = (event != undefined) && $('#options-status').hasClass('active'); // Make it spin self.hasStatusInfo(false) // Load the custom status info callAPI({ mode: 'fullstatus', skip_dashboard: (!statusFullRefresh)*1 }).then(function(data) { // Update basic self.statusInfo.loglevel(data.status.loglevel) self.statusInfo.folders(data.status.folders) // Update the full set if(statusFullRefresh) { self.statusInfo.pystone(data.status.pystone) self.statusInfo.cpumodel(data.status.cpumodel) self.statusInfo.downloaddir(data.status.downloaddir) self.statusInfo.downloaddirspeed(data.status.downloaddirspeed) self.statusInfo.completedir(data.status.completedir) self.statusInfo.completedirspeed(data.status.completedirspeed) self.statusInfo.dnslookup(data.status.dnslookup) self.statusInfo.localipv4(data.status.localipv4) self.statusInfo.publicipv4(data.status.publicipv4) self.statusInfo.ipv6(data.status.ipv6 || glitterTranslate.noneText) // Loaded disk info self.hasPerformanceInfo(true) } // Update the servers if(self.statusInfo.servers().length != data.status.servers.length) { // Only now we can subscribe to the log-level-changes! (only at start) if(self.statusInfo.servers().length == 0) { self.statusInfo.loglevel.subscribe(function(newValue) { // Update log-level callSpecialAPI('./status/change_loglevel/', { loglevel: newValue }); }) } // Empty them, in case of update self.statusInfo.servers([]) // Initial add $.each(data.status.servers, function() { self.statusInfo.servers.push({ 'servername': ko.observable(this.servername), 'serveroptional': ko.observable(this.serveroptional), 'serverpriority': ko.observable(this.serverpriority), 'servertotalconn': ko.observable(this.servertotalconn), 'serverssl': ko.observable(this.serverssl), 'serversslinfo': ko.observable(this.serversslinfo), 'serveractiveconn': ko.observable(this.serveractiveconn), 'servererror': ko.observable(this.servererror), 'serveractive': ko.observable(this.serveractive), 'serverconnections': ko.observableArray(this.serverconnections) }) }) } else { // Update $.each(data.status.servers, function(index) { var activeServer = self.statusInfo.servers()[index]; activeServer.servername(this.servername), activeServer.serveroptional(this.serveroptional), activeServer.serverpriority(this.serverpriority), activeServer.servertotalconn(this.servertotalconn), activeServer.serverssl(this.serverssl), activeServer.serversslinfo(this.serversslinfo), activeServer.serveractiveconn(this.serveractiveconn), activeServer.servererror(this.servererror), activeServer.serveractive(this.serveractive), activeServer.serverconnections(this.serverconnections) }) } // Add tooltips to possible new items if(!isMobile) $('#modal-options [data-tooltip="true"]').tooltip({ trigger: 'hover', container: 'body' }) // Stop it spin self.hasStatusInfo(true) }); } // Do a disk-speedtest self.testDiskSpeed = function(item, event) { self.hasPerformanceInfo(false) // Run it and then display it callSpecialAPI('./status/dashrefresh/').then(function() { self.loadStatusInfo(true, true) }) } // Unblock server self.unblockServer = function(servername) { callSpecialAPI("./status/unblock_server/", { server: servername }).then(function() { $("#modal-options").modal("hide"); }) } // Refresh connections page var connectionRefresh $('.nav-tabs a[href="#options_connections"]').on('shown.bs.tab', function() { // Check size on open checkSize() // Set the interval connectionRefresh = setInterval(function() { // Start small checkSize() // Check if still visible if(!$('#options_connections').is(':visible') && connectionRefresh) { // Stop refreshing clearInterval(connectionRefresh) return } // Only when we show them if(self.showActiveConnections()) { self.loadStatusInfo() } }, self.refreshRate() * 1000) }) // On close of the tab $('.nav-tabs a[href="#options_connections"]').on('hidden.bs.tab', function() { checkSize() }) // Function that handles the actual sizing of connections tab function checkSize() { // Any connections? if(self.showActiveConnections() && $('#options_connections').is(':visible') && $('.table-server-connections').height() > 1) { var mainWidth = $('.main-content').width() $('#modal-options .modal-dialog').width(mainWidth*0.85 > 650 ? mainWidth*0.85 : '') } else { // Small again $('#modal-options .modal-dialog').width('') } } // Make sure Connections get refreshed also after open->close->open $('#modal-options').on('show.bs.modal', function () { // Trigger $('.nav-tabs a[href="#options_connections"]').trigger('shown.bs.tab') }) // Orphaned folder processing self.folderProcess = function(folder, htmlElement) { // Hide tooltips (otherwise they stay forever..) $('#options-orphans [data-tooltip="true"]').tooltip('hide') // Show notification on delete if($(htmlElement.currentTarget).data('action') == 'delete') { showNotification('.main-notification-box-removing', 1000) } else { // Adding back to queue showNotification('.main-notification-box-sendback', 2000) } // Activate callSpecialAPI("./status/" + $(htmlElement.currentTarget).data('action'), { name: $("
").html(folder).text() }).then(function() { // Remove item and load status data $(htmlElement.currentTarget).parent().parent().fadeOut(fadeOnDeleteDuration) // Refresh self.loadStatusInfo(true, true) // Hide notification hideNotification(true) }) } // Orphaned folder deletion of all self.removeAllOrphaned = function() { if(!self.confirmDeleteHistory() || confirm(glitterTranslate.clearWarn)) { // Show notification showNotification('.main-notification-box-removing-multiple', 0, self.statusInfo.folders().length) // Delete them all callSpecialAPI("./status/delete_all/").then(function() { // Remove notifcation and update screen hideNotification(true) self.loadStatusInfo(true, true) }) } } // Orphaned folder adding of all self.addAllOrphaned = function() { if(!self.confirmDeleteHistory() || confirm(glitterTranslate.clearWarn)) { // Show notification showNotification('.main-notification-box-sendback') // Delete them all callSpecialAPI("./status/add_all/").then(function() { // Remove notifcation and update screen hideNotification(true) self.loadStatusInfo(true, true) }) } } // Toggle Glitter's compact layout dynamically self.displayCompact.subscribe(function() { $('body').toggleClass('container-compact') }) // Toggle Glitter's tabbed modus self.displayTabbed.subscribe(function() { $('body').toggleClass('container-tabbed') }) /** SABnzb options **/ // Shutdown self.shutdownSAB = function() { if(confirm(glitterTranslate.shutdown)) { // Show notification and return true to follow the URL showNotification('.main-notification-box-shutdown') return true } } // Restart self.restartSAB = function() { if(!confirm(glitterTranslate.restart)) return; // Call restart function callSpecialAPI("./config/restart/") // Set counter, we need at least 15 seconds self.isRestarting(Math.max(1, Math.floor(15 / self.refreshRate()))); // Force refresh in case of very long refresh-times if(self.refreshRate() > 30) { setTimeout(self.refresh, 30 * 1000) } } // Queue actions self.doQueueAction = function(data, event) { // Event var theAction = $(event.target).data('mode'); // Show notification if available if(['rss_now', 'watched_now'].indexOf(theAction) > -1) { showNotification('.main-notification-box-' + theAction, 2000) } // Send to the API callAPI({ mode: theAction }) } // Repair queue self.repairQueue = function() { if(!confirm(glitterTranslate.repair)) return; // Hide the modal and show the notifucation $("#modal-options").modal("hide"); showNotification('.main-notification-box-queue-repair') // Call the API callSpecialAPI("./config/repair/").then(function() { hideNotification(true) }) } // Force disconnect self.forceDisconnect = function() { // Show notification showNotification('.main-notification-box-disconnect', 3000) // Call API callSpecialAPI("./status/disconnect/").then(function() { $("#modal-options").modal("hide"); }) } /*** Retrieve config information and do startup functions ***/ // Force compact mode as fast as possible if(localStorageGetItem('displayCompact') === 'true') { // Add extra class $('body').addClass('container-compact') } // Tabbed layout? if(localStorageGetItem('displayTabbed') === 'true') { $('body').addClass('container-tabbed') } // Get the speed-limit, refresh rate and server names callAPI({ mode: 'get_config' }).then(function(response) { // Do we use global, or local settings? if(self.useGlobalOptions()) { // Set refreshrate (defaults to 1/s) if(!response.config.misc.refresh_rate) response.config.misc.refresh_rate = 1; self.refreshRate(response.config.misc.refresh_rate.toString()); // Set history limit self.history.paginationLimit(response.config.misc.history_limit.toString()) // Set queue limit self.queue.paginationLimit(response.config.misc.queue_limit.toString()) } // Set bandwidth limit if(!response.config.misc.bandwidth_max) response.config.misc.bandwidth_max = false; self.bandwithLimit(response.config.misc.bandwidth_max); // Save servers (for reporting functionality of OZnzb) self.servers = response.config.servers; // Update message if(newRelease) { self.allMessages.push({ index: 'UpdateMsg', type: glitterTranslate.status['INFO'], text: (''+glitterTranslate.updateAvailable+' '+newRelease+' '), css: 'info' }); } // Message about cache - Not for 5 days if user ignored it if(!response.config.misc.cache_limit && localStorageGetItem('CacheMsg')*1+(1000*3600*24*5) < Date.now()) { self.allMessages.push({ index: 'CacheMsg', type: glitterTranslate.status['INFO'], text: (''+glitterTranslate.useCache.replace(/
/g, " ")+'
'), css: 'info', clear: function() { self.clearMessages('CacheMsg')} }); } // Message about tips and tricks, only once if(response.config.misc.notified_new_skin < 2) { self.allMessages.push({ index: 'TipsMsgV110', type: glitterTranslate.status['INFO'], text: glitterTranslate.glitterTips + ' Glitter Tips and Tricks ', css: 'info', clear: function() { // Update the config to not show again callAPI({ mode: 'set_config', section: 'misc', keyword: 'notified_new_skin', value: 2 }) // Remove the actual message self.clearMessages('TipsMsgV110') } }); } }) // Orphaned folder check - Not for 5 days if user ignored it var orphanMsg = localStorageGetItem('OrphanedMsg')*1+(1000*3600*24*5) < Date.now(); // Delay the check if(orphanMsg) { setTimeout(self.loadStatusInfo, 200); } // On any status load we check Orphaned folders self.hasStatusInfo.subscribe(function(finishedLoading) { // Loaded or just starting? if(!finishedLoading) return; // Orphaned folders? If user clicked away we check again in 5 days if(self.statusInfo.folders().length >= 3 && orphanMsg) { // Check if not already there if(!ko.utils.arrayFirst(self.allMessages(), function(item) { return item.index == 'OrphanedMsg' })) { self.allMessages.push({ index: 'OrphanedMsg', type: glitterTranslate.status['INFO'], text: glitterTranslate.orphanedJobsMsg + ' ', css: 'info', clear: function() { self.clearMessages('OrphanedMsg')} }); } } else { // Remove any message, if it was there self.allMessages.remove(function(item) { return item.index == 'OrphanedMsg'; }) } }) // Message about localStorage not being enabled every 20 days if(!hasLocalStorage && localStorageGetItem('LocalStorageMsg')*1+(1000*3600*24*20) < Date.now()) { self.allMessages.push({ index: 'LocalStorageMsg', type: glitterTranslate.status['WARNING'].replace(':', ''), text: glitterTranslate.noLocalStorage, css: 'warning', clear: function() { self.clearMessages('LocalStorageMsg')} }); } /*** Date-stuff ***/ moment.locale(displayLang); // Fill the basic info for date-formats with current date-time $('[name="general-date-format"] option').each(function() { $(this).text(displayDateTime('', $(this).val()), '') }) // Update the date every minute setInterval(function() { $('[data-timestamp]').each(function() { $(this).text(displayDateTime($(this).data('timestamp'), self.dateFormat(), 'X')) }) }, 60*1000) /*** End of main functions, start of the fun! ***/ // Trigger first refresh self.interval = setTimeout(self.refresh, parseInt(self.refreshRate()) * 1000); // And refresh now! self.refresh() // Activate tooltips if(!isMobile) $('[data-tooltip="true"]').tooltip({ trigger: 'hover', container: 'body' }) }SABnzbd-2.3.2/interfaces/Glitter/templates/static/javascripts/glitter.queue.js0000644000000000000000000006273713217005257025656 0ustar 00000000000000/** Model for the whole Queue with all it's items **/ function QueueListModel(parent) { // Internal var's var self = this; self.parent = parent; self.dragging = false; self.rawCatList = []; self.rawScriptList = []; // Because SABNZB returns the name // But when you want to set Priority you need the number.. self.priorityName = []; self.priorityName["Force"] = 2; self.priorityName["High"] = 1; self.priorityName["Normal"] = 0; self.priorityName["Low"] = -1; self.priorityName["Stop"] = -4; self.priorityOptions = ko.observableArray([ { value: 2, name: glitterTranslate.priority["Force"] }, { value: 1, name: glitterTranslate.priority["High"] }, { value: 0, name: glitterTranslate.priority["Normal"] }, { value: -1, name: glitterTranslate.priority["Low"] }, { value: -4, name: glitterTranslate.priority["Stop"] } ]); self.processingOptions = ko.observableArray([ { value: 0, name: glitterTranslate.pp["Download"] }, { value: 1, name: glitterTranslate.pp["+Repair"] }, { value: 2, name: glitterTranslate.pp["+Unpack"] }, { value: 3, name: glitterTranslate.pp["+Delete"] } ]); // External var's self.queueItems = ko.observableArray([]); self.totalItems = ko.observable(0); self.isMultiEditing = ko.observable(false); self.isLoading = ko.observable(false).extend({ rateLimit: 100 }); self.multiEditItems = ko.observableArray([]); self.categoriesList = ko.observableArray([]); self.scriptsList = ko.observableArray([]); self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 200, method: "notifyWhenChangesStop" } }); self.paginationLimit = ko.observable(20).extend({ persist: 'queuePaginationLimit' }); self.pagination = new paginationModel(self); // Don't update while dragging self.shouldUpdate = function() { return !self.dragging; } self.dragStart = function() { self.dragging = true; } self.dragStop = function(event) { // Remove that extra label $(event.target).parent().removeClass('table-active-sorting') // Wait a little before refreshing again (prevents jumping) setTimeout(function() { self.dragging = false; }, 500) } // Update slots from API data self.updateFromData = function(data) { // Get all ID's var itemIds = $.map(self.queueItems(), function(i) { return i.id; }); // Did the category-list change? // Otherwise KO will send updates to all in the dropdown are a hugggeeee slowdown on initial load! // Only loading on click cuts half the speed (especially on large queues) self.toggleDropdown = function(item, event) { self.hasDropdown(true) // Keep it open! keepOpen(event.target) } // Change of settings self.changeCat = function(item, event) { callAPI({ mode: 'change_cat', value: item.id, value2: item.category() }).then(function() { // Hide all tooltips before we refresh $('.queue-item-settings li').filter('[data-tooltip="true"]').tooltip('hide') self.parent.parent.refresh() }) } self.changeScript = function(item) { // Not on empty handlers if(!item.script() || parent.scriptsList().length <= 1) return; callAPI({ mode: 'change_script', value: item.id, value2: item.script() }) } self.changeProcessing = function(item) { callAPI({ mode: 'change_opts', value: item.id, value2: item.unpackopts() }) } self.changePriority = function(item, event) { // Not if we are fetching extra blocks for repair! if(item.isFetchingBlocks) return callAPI({ mode: 'queue', name: 'priority', value: item.id, value2: item.priority() }).then(function() { // Hide all tooltips before we refresh $('.queue-item-settings li').filter('[data-tooltip="true"]').tooltip('hide') self.parent.parent.refresh() }) } // Remove 1 download from queue self.removeDownload = function(item, event) { // Confirm and remove if(!self.parent.parent.confirmDeleteQueue() || confirm(glitterTranslate.removeDow1)) { var itemToDelete = this; // Show notification showNotification('.main-notification-box-removing') callAPI({ mode: 'queue', name: 'delete', del_files: 1, value: item.id }).then(function(response) { // Fade and remove $(event.currentTarget).parent().parent().fadeOut(fadeOnDeleteDuration, function() { // Make sure no flickering (if there are more items left) and then remove self.parent.isLoading(self.parent.totalItems() > 1) parent.queueItems.remove(itemToDelete); parent.multiEditItems.remove(function(inList) { return inList.id == itemToDelete.id; }) self.parent.parent.refresh(); // Hide notifcation hideNotification(true) }) }); } }; }SABnzbd-2.3.2/interfaces/Glitter/templates/static/javascripts/jquery-ui.min.js0000644000000000000000000013437213217005257025570 0ustar 00000000000000/*! jQuery UI - v1.12.1 - 2016-09-16 * http://jqueryui.com * Includes: widget.js, data.js, keycode.js, scroll-parent.js, widgets/sortable.js, widgets/mouse.js, widgets/slider.js * Copyright jQuery Foundation and other contributors; Licensed MIT */ (function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){t.ui=t.ui||{},t.ui.version="1.12.1";var e=0,i=Array.prototype.slice;t.cleanData=function(e){return function(i){var s,n,o;for(o=0;null!=(n=i[o]);o++)try{s=t._data(n,"events"),s&&s.remove&&t(n).triggerHandler("remove")}catch(a){}e(i)}}(t.cleanData),t.widget=function(e,i,s){var n,o,a,r={},l=e.split(".")[0];e=e.split(".")[1];var h=l+"-"+e;return s||(s=i,i=t.Widget),t.isArray(s)&&(s=t.extend.apply(null,[{}].concat(s))),t.expr[":"][h.toLowerCase()]=function(e){return!!t.data(e,h)},t[l]=t[l]||{},n=t[l][e],o=t[l][e]=function(t,e){return this._createWidget?(arguments.length&&this._createWidget(t,e),void 0):new o(t,e)},t.extend(o,n,{version:s.version,_proto:t.extend({},s),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(s,function(e,s){return t.isFunction(s)?(r[e]=function(){function t(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}return function(){var e,i=this._super,o=this._superApply;return this._super=t,this._superApply=n,e=s.apply(this,arguments),this._super=i,this._superApply=o,e}}(),void 0):(r[e]=s,void 0)}),o.prototype=t.widget.extend(a,{widgetEventPrefix:n?a.widgetEventPrefix||e:e},r,{constructor:o,namespace:l,widgetName:e,widgetFullName:h}),n?(t.each(n._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete n._childConstructors):i._childConstructors.push(o),t.widget.bridge(e,o),o},t.widget.extend=function(e){for(var s,n,o=i.call(arguments,1),a=0,r=o.length;r>a;a++)for(s in o[a])n=o[a][s],o[a].hasOwnProperty(s)&&void 0!==n&&(e[s]=t.isPlainObject(n)?t.isPlainObject(e[s])?t.widget.extend({},e[s],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,s){var n=s.prototype.widgetFullName||e;t.fn[e]=function(o){var a="string"==typeof o,r=i.call(arguments,1),l=this;return a?this.length||"instance"!==o?this.each(function(){var i,s=t.data(this,n);return"instance"===o?(l=s,!1):s?t.isFunction(s[o])&&"_"!==o.charAt(0)?(i=s[o].apply(s,r),i!==s&&void 0!==i?(l=i&&i.jquery?l.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+o+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+o+"'")}):l=void 0:(r.length&&(o=t.widget.extend.apply(null,[o].concat(r))),this.each(function(){var e=t.data(this,n);e?(e.option(o||{}),e._init&&e._init()):t.data(this,n,new s(o,this))})),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{classes:{},disabled:!1,create:null},_createWidget:function(i,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=e++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),i),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var l=s.match(/^([\w:-]*)\s*(.*)$/),h=l[1]+o.eventNamespace,c=l[2];c?n.on(h,c,r):i.on(h,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var s=!1;t(document).on("mouseup",function(){s=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!s){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,n=1===e.which,o="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return n&&!o&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),s=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,s=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.widget("ui.sortable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(t,e,i){return t>=e&&e+i>t},_isFloating:function(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))},_create:function(){this.containerCache={},this._addClass("ui-sortable"),this.refresh(),this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(t,e){this._super(t,e),"handle"===t&&this._setHandleClassName()},_setHandleClassName:function(){var e=this;this._removeClass(this.element.find(".ui-sortable-handle"),"ui-sortable-handle"),t.each(this.items,function(){e._addClass(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item,"ui-sortable-handle")})},_destroy:function(){this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):void 0}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this._addClass(this.helper,"ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp(new t.Event("mouseup",{target:null})),"original"===this.options.helper?(this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,l=r+t.height,h=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+h>r&&l>s+h,d="y"===this.options.axis||e+c>o&&a>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&l>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var e,i,s="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top,t.height),n="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left,t.width),o=s&&n;return o?(e=this._getDragVerticalDirection(),i=this._getDragHorizontalDirection(),this.floating?"right"===i||"down"===e?2:1:e&&("down"===e?2:1)):!1},_intersectsWithSides:function(t){var e=this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&e||"up"===s&&!e)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){function i(){r.push(this)}var s,n,o,a,r=[],l=[],h=this._connectWith();if(h&&e)for(s=h.length-1;s>=0;s--)for(o=t(h[s],this.document[0]),n=o.length-1;n>=0;n--)a=t.data(o[n],this.widgetFullName),a&&a!==this&&!a.options.disabled&&l.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(l.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=l.length-1;s>=0;s--)l[s][0].each(i);return t(r)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,l,h,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i],this.document[0]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,h=r.length;h>s;s++)l=t(r[s]),l.data(this.widgetName+"-item",a),c.push({item:l,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.floating=this.items.length?"x"===this.options.axis||this._isFloating(this.items[0].item):!1,this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]);return e._addClass(n,"ui-sortable-placeholder",i||e.currentItem[0].className)._removeClass(n,"ui-sortable-helper"),"tbody"===s?e._createTrPlaceholder(e.currentItem.find("tr").eq(0),t("",e.document[0]).appendTo(n)):"tr"===s?e._createTrPlaceholder(e.currentItem,n):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_createTrPlaceholder:function(e,i){var s=this;e.children().each(function(){t(" ",s.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(i)})},_contactContainers:function(e){var i,s,n,o,a,r,l,h,c,u,d=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!t.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(d&&t.contains(this.containers[i].element[0],d.element[0]))continue;d=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",e,this._uiHash(this)),this.containers[i].containerCache.over=0);if(d)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,o=null,c=d.floating||this._isFloating(this.currentItem),a=c?"left":"top",r=c?"width":"height",u=c?"pageX":"pageY",s=this.items.length-1;s>=0;s--)t.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(l=this.items[s].item.offset()[a],h=!1,e[u]-l>this.items[s][r]/2&&(h=!0),n>Math.abs(e[u]-l)&&(n=Math.abs(e[u]-l),o=this.items[s],this.direction=h?"up":"down"));if(!o&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;o?this._rearrange(e,o,null,!0):this._rearrange(e,null,this.containers[p].element,!0),this._trigger("change",e,this._uiHash()),this.containers[p]._trigger("change",e,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===this.document[0].body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,"document"===n.containment?this.document.width():this.window.width()-this.helperProportions.width-this.margins.left,("document"===n.containment?this.document.height()||document.body.parentNode.scrollHeight:this.window.height()||this.document[0].body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s} },_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,l=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.leftthis.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():l?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():l?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){function i(t,e,i){return function(s){i._trigger(t,s,e._uiHash(e))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&n.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||n.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(n.push(function(t){this._trigger("remove",t,this._uiHash())}),n.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)e||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!e){for(s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}}),t.widget("ui.slider",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"slide",options:{animate:!1,classes:{"ui-slider":"ui-corner-all","ui-slider-handle":"ui-corner-all","ui-slider-range":"ui-corner-all ui-widget-header"},distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},numPages:5,_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this._calculateNewMax(),this._addClass("ui-slider ui-slider-"+this.orientation,"ui-widget ui-widget-content"),this._refresh(),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var e,i,s=this.options,n=this.element.find(".ui-slider-handle"),o="",a=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),e=n.length;i>e;e++)a.push(o);this.handles=n.add(t(a.join("")).appendTo(this.element)),this._addClass(this.handles,"ui-slider-handle","ui-state-default"),this.handle=this.handles.eq(0),this.handles.each(function(e){t(this).data("ui-slider-handle-index",e).attr("tabIndex",0)})},_createRange:function(){var e=this.options;e.range?(e.range===!0&&(e.values?e.values.length&&2!==e.values.length?e.values=[e.values[0],e.values[0]]:t.isArray(e.values)&&(e.values=e.values.slice(0)):e.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?(this._removeClass(this.range,"ui-slider-range-min ui-slider-range-max"),this.range.css({left:"",bottom:""})):(this.range=t("
").appendTo(this.element),this._addClass(this.range,"ui-slider-range")),("min"===e.range||"max"===e.range)&&this._addClass(this.range,"ui-slider-range-"+e.range)):(this.range&&this.range.remove(),this.range=null)},_setupEvents:function(){this._off(this.handles),this._on(this.handles,this._handleEvents),this._hoverable(this.handles),this._focusable(this.handles)},_destroy:function(){this.handles.remove(),this.range&&this.range.remove(),this._mouseDestroy()},_mouseCapture:function(e){var i,s,n,o,a,r,l,h,c=this,u=this.options;return u.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:e.pageX,y:e.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(e){var i=Math.abs(s-c.values(e));(n>i||n===i&&(e===c._lastChangedValue||c.values(e)===u.min))&&(n=i,o=t(this),a=e)}),r=this._start(e,a),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=a,this._addClass(o,null,"ui-state-active"),o.trigger("focus"),l=o.offset(),h=!t(e.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=h?{left:0,top:0}:{left:e.pageX-l.left-o.width()/2,top:e.pageY-l.top-o.height()/2-(parseInt(o.css("borderTopWidth"),10)||0)-(parseInt(o.css("borderBottomWidth"),10)||0)+(parseInt(o.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(e,a,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(t){var e={x:t.pageX,y:t.pageY},i=this._normValueFromMouse(e);return this._slide(t,this._handleIndex,i),!1},_mouseStop:function(t){return this._removeClass(this.handles,null,"ui-state-active"),this._mouseSliding=!1,this._stop(t,this._handleIndex),this._change(t,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(t){var e,i,s,n,o;return"horizontal"===this.orientation?(e=this.elementSize.width,i=t.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,i=t.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/e,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),o=this._valueMin()+s*n,this._trimAlignValue(o)},_uiHash:function(t,e,i){var s={handle:this.handles[t],handleIndex:t,value:void 0!==e?e:this.value()};return this._hasMultipleValues()&&(s.value=void 0!==e?e:this.values(t),s.values=i||this.values()),s},_hasMultipleValues:function(){return this.options.values&&this.options.values.length},_start:function(t,e){return this._trigger("start",t,this._uiHash(e))},_slide:function(t,e,i){var s,n,o=this.value(),a=this.values();this._hasMultipleValues()&&(n=this.values(e?0:1),o=this.values(e),2===this.options.values.length&&this.options.range===!0&&(i=0===e?Math.min(n,i):Math.max(n,i)),a[e]=i),i!==o&&(s=this._trigger("slide",t,this._uiHash(e,i,a)),s!==!1&&(this._hasMultipleValues()?this.values(e,i):this.value(i)))},_stop:function(t,e){this._trigger("stop",t,this._uiHash(e))},_change:function(t,e){this._keySliding||this._mouseSliding||(this._lastChangedValue=e,this._trigger("change",t,this._uiHash(e)))},value:function(t){return arguments.length?(this.options.value=this._trimAlignValue(t),this._refreshValue(),this._change(null,0),void 0):this._value()},values:function(e,i){var s,n,o;if(arguments.length>1)return this.options.values[e]=this._trimAlignValue(i),this._refreshValue(),this._change(null,e),void 0;if(!arguments.length)return this._values();if(!t.isArray(arguments[0]))return this._hasMultipleValues()?this._values(e):this.value();for(s=this.options.values,n=arguments[0],o=0;s.length>o;o+=1)s[o]=this._trimAlignValue(n[o]),this._change(null,o);this._refreshValue()},_setOption:function(e,i){var s,n=0;switch("range"===e&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),t.isArray(this.options.values)&&(n=this.options.values.length),this._super(e,i),e){case"orientation":this._detectOrientation(),this._removeClass("ui-slider-horizontal ui-slider-vertical")._addClass("ui-slider-"+this.orientation),this._refreshValue(),this.options.range&&this._refreshRange(i),this.handles.css("horizontal"===i?"bottom":"left","");break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=n-1;s>=0;s--)this._change(null,s);this._animateOff=!1;break;case"step":case"min":case"max":this._animateOff=!0,this._calculateNewMax(),this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_setOptionDisabled:function(t){this._super(t),this._toggleClass(null,"ui-state-disabled",!!t)},_value:function(){var t=this.options.value;return t=this._trimAlignValue(t)},_values:function(t){var e,i,s;if(arguments.length)return e=this.options.values[t],e=this._trimAlignValue(e);if(this._hasMultipleValues()){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(t){if(this._valueMin()>=t)return this._valueMin();if(t>=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,i=(t-this._valueMin())%e,s=t-i;return 2*Math.abs(i)>=e&&(s+=i>0?e:-e),parseFloat(s.toFixed(5))},_calculateNewMax:function(){var t=this.options.max,e=this._valueMin(),i=this.options.step,s=Math.round((t-e)/i)*i;t=s+e,t>this.options.max&&(t-=i),this.max=parseFloat(t.toFixed(this._precision()))},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_valueMin:function(){return this.options.min},_valueMax:function(){return this.max},_refreshRange:function(t){"vertical"===t&&this.range.css({width:"",left:""}),"horizontal"===t&&this.range.css({height:"",bottom:""})},_refreshValue:function(){var e,i,s,n,o,a=this.options.range,r=this.options,l=this,h=this._animateOff?!1:r.animate,c={};this._hasMultipleValues()?this.handles.each(function(s){i=100*((l.values(s)-l._valueMin())/(l._valueMax()-l._valueMin())),c["horizontal"===l.orientation?"left":"bottom"]=i+"%",t(this).stop(1,1)[h?"animate":"css"](c,r.animate),l.options.range===!0&&("horizontal"===l.orientation?(0===s&&l.range.stop(1,1)[h?"animate":"css"]({left:i+"%"},r.animate),1===s&&l.range[h?"animate":"css"]({width:i-e+"%"},{queue:!1,duration:r.animate})):(0===s&&l.range.stop(1,1)[h?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&l.range[h?"animate":"css"]({height:i-e+"%"},{queue:!1,duration:r.animate}))),e=i}):(s=this.value(),n=this._valueMin(),o=this._valueMax(),i=o!==n?100*((s-n)/(o-n)):0,c["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[h?"animate":"css"](c,r.animate),"min"===a&&"horizontal"===this.orientation&&this.range.stop(1,1)[h?"animate":"css"]({width:i+"%"},r.animate),"max"===a&&"horizontal"===this.orientation&&this.range.stop(1,1)[h?"animate":"css"]({width:100-i+"%"},r.animate),"min"===a&&"vertical"===this.orientation&&this.range.stop(1,1)[h?"animate":"css"]({height:i+"%"},r.animate),"max"===a&&"vertical"===this.orientation&&this.range.stop(1,1)[h?"animate":"css"]({height:100-i+"%"},r.animate))},_handleEvents:{keydown:function(e){var i,s,n,o,a=t(e.target).data("ui-slider-handle-index");switch(e.keyCode){case t.ui.keyCode.HOME:case t.ui.keyCode.END:case t.ui.keyCode.PAGE_UP:case t.ui.keyCode.PAGE_DOWN:case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(e.preventDefault(),!this._keySliding&&(this._keySliding=!0,this._addClass(t(e.target),null,"ui-state-active"),i=this._start(e,a),i===!1))return}switch(o=this.options.step,s=n=this._hasMultipleValues()?this.values(a):this.value(),e.keyCode){case t.ui.keyCode.HOME:n=this._valueMin();break;case t.ui.keyCode.END:n=this._valueMax();break;case t.ui.keyCode.PAGE_UP:n=this._trimAlignValue(s+(this._valueMax()-this._valueMin())/this.numPages);break;case t.ui.keyCode.PAGE_DOWN:n=this._trimAlignValue(s-(this._valueMax()-this._valueMin())/this.numPages);break;case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:if(s===this._valueMax())return;n=this._trimAlignValue(s+o);break;case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(s===this._valueMin())return;n=this._trimAlignValue(s-o)}this._slide(e,a,n)},keyup:function(e){var i=t(e.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(e,i),this._change(e,i),this._removeClass(t(e.target),null,"ui-state-active"))}}})});SABnzbd-2.3.2/interfaces/Glitter/templates/static/javascripts/jquery.min.js0000644000000000000000000024711113217005257025151 0ustar 00000000000000/*! jQuery v2.2.4 | (c) jQuery Foundation | jquery.org/license */ !function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isPlainObject:function(a){var b;if("object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype||{},"isPrototypeOf"))return!1;for(b in a);return void 0===b||k.call(a,b)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=d.createElement("script"),b.text=a,d.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:h.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(d=e.call(arguments,2),f=function(){return a.apply(b||this,d.concat(e.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return h.call(b,a)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&f.parentNode&&(this.length=1,this[0]=f),this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?void 0!==c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?h.call(n(a),this[0]):h.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||n.uniqueSort(e),D.test(a)&&e.reverse()),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.removeEventListener("DOMContentLoaded",J),a.removeEventListener("load",J),n.ready()}n.ready.promise=function(b){return I||(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(n.ready):(d.addEventListener("DOMContentLoaded",J),a.addEventListener("load",J))),I.promise(b)},n.ready.promise();var K=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)K(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},L=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function M(){this.expando=n.expando+M.uid++}M.uid=1,M.prototype={register:function(a,b){var c=b||{};return a.nodeType?a[this.expando]=c:Object.defineProperty(a,this.expando,{value:c,writable:!0,configurable:!0}),a[this.expando]},cache:function(a){if(!L(a))return{};var b=a[this.expando];return b||(b={},L(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[b]=c;else for(d in b)e[d]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=a[this.expando];if(void 0!==f){if(void 0===b)this.register(a);else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in f?d=[b,e]:(d=e,d=d in f?[d]:d.match(G)||[])),c=d.length;while(c--)delete f[d[c]]}(void 0===b||n.isEmptyObject(f))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!n.isEmptyObject(b)}};var N=new M,O=new M,P=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Q=/[A-Z]/g;function R(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Q,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:P.test(c)?n.parseJSON(c):c; }catch(e){}O.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),R(f,d,e[d])));N.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){O.set(this,a)}):K(this,function(b){var c,d;if(f&&void 0===b){if(c=O.get(f,a)||O.get(f,a.replace(Q,"-$&").toLowerCase()),void 0!==c)return c;if(d=n.camelCase(a),c=O.get(f,d),void 0!==c)return c;if(c=R(f,d,void 0),void 0!==c)return c}else d=n.camelCase(a),this.each(function(){var c=O.get(this,d);O.set(this,d,b),a.indexOf("-")>-1&&void 0!==c&&O.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){O.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=N.get(a,b),c&&(!d||n.isArray(c)?d=N.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return N.get(a,c)||N.access(a,c,{empty:n.Callbacks("once memory").add(function(){N.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length",""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};$.optgroup=$.option,$.tbody=$.tfoot=$.colgroup=$.caption=$.thead,$.th=$.td;function _(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function aa(a,b){for(var c=0,d=a.length;d>c;c++)N.set(a[c],"globalEval",!b||N.get(b[c],"globalEval"))}var ba=/<|&#?\w+;/;function ca(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],o=0,p=a.length;p>o;o++)if(f=a[o],f||0===f)if("object"===n.type(f))n.merge(m,f.nodeType?[f]:f);else if(ba.test(f)){g=g||l.appendChild(b.createElement("div")),h=(Y.exec(f)||["",""])[1].toLowerCase(),i=$[h]||$._default,g.innerHTML=i[1]+n.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;n.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",o=0;while(f=m[o++])if(d&&n.inArray(f,d)>-1)e&&e.push(f);else if(j=n.contains(f.ownerDocument,f),g=_(l.appendChild(f),"script"),j&&aa(g),c){k=0;while(f=g[k++])Z.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ja(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ha;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return"undefined"!=typeof n&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(G)||[""],j=b.length;while(j--)h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.hasData(a)&&N.get(a);if(r&&(i=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&N.remove(a,"handle events")}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(N.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,la=/\s*$/g;function pa(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function qa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function ra(a){var b=na.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function sa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(N.hasData(a)&&(f=N.access(a),g=N.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}O.hasData(a)&&(h=O.access(a),i=n.extend({},h),O.set(b,i))}}function ta(a,b){var c=b.nodeName.toLowerCase();"input"===c&&X.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function ua(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&ma.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),ua(f,b,c,d)});if(o&&(e=ca(b,a[0].ownerDocument,!1,a,d),g=e.firstChild,1===e.childNodes.length&&(e=g),g||d)){for(h=n.map(_(e,"script"),qa),i=h.length;o>m;m++)j=e,m!==p&&(j=n.clone(j,!0,!0),i&&n.merge(h,_(j,"script"))),c.call(a[m],j,m);if(i)for(k=h[h.length-1].ownerDocument,n.map(h,ra),m=0;i>m;m++)j=h[m],Z.test(j.type||"")&&!N.access(j,"globalEval")&&n.contains(k,j)&&(j.src?n._evalUrl&&n._evalUrl(j.src):n.globalEval(j.textContent.replace(oa,"")))}return a}function va(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(_(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&aa(_(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(ka,"<$1>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=_(h),f=_(a),d=0,e=f.length;e>d;d++)ta(f[d],g[d]);if(b)if(c)for(f=f||_(a),g=g||_(h),d=0,e=f.length;e>d;d++)sa(f[d],g[d]);else sa(a,h);return g=_(h,"script"),g.length>0&&aa(g,!i&&_(a,"script")),h},cleanData:function(a){for(var b,c,d,e=n.event.special,f=0;void 0!==(c=a[f]);f++)if(L(c)){if(b=c[N.expando]){if(b.events)for(d in b.events)e[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);c[N.expando]=void 0}c[O.expando]&&(c[O.expando]=void 0)}}}),n.fn.extend({domManip:ua,detach:function(a){return va(this,a,!0)},remove:function(a){return va(this,a)},text:function(a){return K(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.appendChild(a)}})},prepend:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(_(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return K(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!la.test(a)&&!$[(Y.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(_(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return ua(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(_(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),f=e.length-1,h=0;f>=h;h++)c=h===f?this:this.clone(!0),n(e[h])[b](c),g.apply(d,c.get());return this.pushStack(d)}});var wa,xa={HTML:"block",BODY:"block"};function ya(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function za(a){var b=d,c=xa[a];return c||(c=ya(a,b),"none"!==c&&c||(wa=(wa||n("

$T('wizard-previous')
SABnzbd-2.3.2/interfaces/wizard/README.TXT0000644000000000000000000000153413217005257016115 0ustar 00000000000000# # Copyright 2009 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # # This is the quick setup wizard for SABnzbd # It is used when first starting up sabnzbd # SABnzbd-2.3.2/interfaces/wizard/two.html0000644000000000000000000000340113217004754016252 0ustar 00000000000000
$T('wizard-version') $version

$T('wizard-quickstart')


$T('wizard-complete')


$T('wizard-tip1') $T('wizard-tip2')

$T('wizard-tip4')

$url

$T('opt-complete_dir')

$complete_dir

$T('opt-download_dir')

$download_dir

$T('wizard-tip-wiki') $T('menu-wiki')


$T('wizard-goto')
SABnzbd-2.3.2/interfaces/wizard/static/style.css0000644000000000000000000000577213217005257017730 0ustar 00000000000000body { background-color: #E4E4E4; text-align: center; } .container { max-width: 1000px; border: 1px solid rgba(0, 0, 0, 0.2); background-color: #fff; text-align: left; } #inner { background-color: #fff; padding: 4px 32px 20px 32px; } #content { min-height: 550px; } #logo { z-index: 40; margin-bottom: -39px; margin-top: 20px; } #logo svg { height: 55px; width: 198px; } .language { min-width: 150px; width: 18%; padding: 1em 0em; margin: 5px 5px; text-align: center; float: left; } .language:hover { background-color: #E4E4E4; } .float { float: left; } .clear { clear: left; } .spacer { clear: both; } .inline { display: inline; } .quoteBlock { padding: 12px; margin-top: 1px; margin-bottom: 15px; background-color: #f5f5f5; } .quoteBlock a, a[target="_blank"] { text-decoration: underline !important; } .success { color: #00cc22; } .failed { color: red !important; } #rightGreyText { color: #ccc; width: 100%; text-align: right; padding-top: 3px; font-style: italic; } .indented { padding-left: 10px; } label { cursor: pointer; } .input-checkbox { padding-top: 7px !important; } .input-checkbox input+.help-block { display: none; } .input-checkbox input:checked+.help-block { display: block; float: right; margin: 0; } .sup { vertical-align: sup !important; } .align-right { text-align: right; } .align-center { text-align: center; } .float-center { float: center; } .unselected, .selected { display: inline-block; } .unselected { padding: 6px 10px 6px 10px; border: 1px solid #636363; margin-left: 8px; margin-right: 8px; color: #636363; } .selected { padding: 6px 10px 6px 10px; color: white; background-color: #636363; border: 1px solid #636363; margin-left: 8px; margin-right: 8px; } .bigger { font-size: 14px; } .padded { padding: 12px; } .bigger input { font-size: 16px; } .required-star { color: red; } .full-width { width: 100%; } .bigbutton { font-size: 18px !important; } .correct { border: 2px solid #00cc22; } .incorrect { border: 2px solid red; } .hidden { display: none !important; } .text-input { width: 130px; } .text-input-wide { width: 230px; } .text-input-thin, #server-hidden-settings input[type="number"] { width: 100px; } .input-group-bw { width: 150px; } .disabled-text { text-decoration: line-through; color: #ccc; } #serverResponse { padding: 6px 10px; } #host-tip { margin-bottom: 5px; } .error-text { display: inline; color: red; } #bandwidth { display: inline-block; } /*** Bootstrap overwrites ***/ * { border-radius: 0 !important; } #content a, #content a:hover, #content a:active, #content a:visited, #serverResponse { color: #555; } .btn { box-shadow: 1px 1px 1px rgba(0, 0, 0, .1) !important; min-width: 150px; } .btn .glyphicon, a .glyphicon { top: 2px; } small { color: #777; }SABnzbd-2.3.2/interfaces/wizard/static/javascript/checkserver.js0000644000000000000000000000464113217005257023060 0ustar 00000000000000function checkRequired() { if ($("#host").val() && $("#connections").val()) { $("#next-button").removeClass('disabled') return true; } else { $("#next-button").addClass('disabled') return false; } } $(document).ready(function() { // Add tooltips $('[data-toggle="tooltip"]').tooltip() // On form-submit $("#serverTest").click(function() { $('#serverResponse').html(txtChecking); $.getJSON( "../tapi?mode=config&name=test_server&output=json", $("form").serialize(), function(result) { if (result.value.result) { r = ' ' + result.value.message + ''; } else { r = ' ' + result.value.message + ''; } r = r.replace('https://sabnzbd.org/certificate-errors', 'https://sabnzbd.org/certificate-errors') $('#serverResponse').html(r); } ); return false; }); $("#port, #connections").bind('keyup blur', function() { if (this.value > 0) { $(this).removeClass("incorrect"); $(this).addClass("correct"); } else { $(this).removeClass("correct"); $(this).addClass("incorrect"); } checkRequired() }); $("#host, #username, #password").bind('keyup blur', function() { if (this.value) { $(this).removeClass("incorrect"); $(this).addClass("correct"); } else { $(this).removeClass("correct"); $(this).addClass("incorrect"); } checkRequired(); }); $('#ssl').click(function() { if(this.checked) { // Enabled SSL change port when not already a custom port if($('#port').val() == '119') { $('#port').val('563') } } else { // Remove SSL port if($('#port').val() == '563') { $('#port').val('119') } } }) checkRequired() $('form').submit(function(event) { // Double check if(!checkRequired()) { event.preventDefault(); } }) });SABnzbd-2.3.2/licenses/License-CherryPy.txt0000644000000000000000000000400713217005256016624 0ustar 00000000000000The module CherryPy is (c) CherryPy team. The module has been stripped of its Tutorial and Test directories. We embed CherryPy in SABnzbd, because CherryPy releases lack backward compatibility and cannot be installed as parallel versions into the system's Python installation. Home of the module: http://www.cherrypy.org It is covered by the following license. ------------------------------------------------------------------------- Copyright (c) 2004-2016, CherryPy Team (team@cherrypy.org) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the CherryPy Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------- SABnzbd-2.3.2/licenses/License-configobj.txt0000644000000000000000000000363313217005256017023 0ustar 00000000000000The module configobj.py is written by Michael Foord and Nicola Larosa. Home of the module: http://www.voidspace.org.uk/python/configobj-api/pythonutils.configobj-pysrc.html It is covered by the following license. ------------------------------------------------------------------------- Copyright (c) 2003-2007, Michael Foord and Nicola Larosa All rights reserved. E-mail : fuzzyman AT voidspace DOT org DOT uk Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Michael Foord nor the name of Voidspace may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------- SABnzbd-2.3.2/licenses/License-feedparser.txt0000644000000000000000000000321113217005256017173 0ustar 00000000000000The module feedparser.py-5.1 is (c) Mark Pilgrim and Kurt McKee We use only the feedparser itself, all additional material was removed. Home of the feedparser module: https://code.google.com/p/feedparser It is covered by the following license. ----- begin license block ----- Copyright (c) 2010-2011 Kurt McKee Copyright (c) 2002-2008 Mark Pilgrim All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.""" ----- end license block ----- SABnzbd-2.3.2/licenses/License-gntp.txt0000644000000000000000000000246513217005256016035 0ustar 00000000000000The module gntp is (C) Paul Traylor Home of the module: https://github.com/kfdm/gntp/ It is covered by the following license. ------------------------------------------------------------------------- Copyright (c) 2011 Paul Traylor Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------- SABnzbd-2.3.2/licenses/License-kronos.txt0000644000000000000000000000350313217005256016372 0ustar 00000000000000Kronos.py is written by Irmen de Jong. Retreived from: http://www.razorvine.net/download/kronos.py Quote from the module: """ This version has been extracted from the Turbogears source repository and slightly changed to be completely stand-alone again. Also some fixes have been made to make it work on Python 2.6 (sched module changes). The version in Turbogears is based on the original stand-alone Kronos. """ It is covered by the following license. http://www.opensource.org/licenses/mit-license.php -------------------------------------------------------------------------------------------- The MIT License Kronos.py is Copyright (c) Irmen de Jong. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------------------------------------------SABnzbd-2.3.2/licenses/License-pybonjour.txt0000644000000000000000000000040613217005256017105 0ustar 00000000000000The module pybonjour is (C) Christopher Stawarz Version: 1.1.1 May 8, 2008 Home of the module: http://pseudogreen.org/bzr/pybonjour/ It is covered by the following license: "pybonjour is free software, distributed under the MIT license." SABnzbd-2.3.2/licenses/License-pynewsleecher.txt0000644000000000000000000000057313217005256017740 0ustar 00000000000000The original author of SABnzbd based his work on Pynewsleecher by Freddy@madcowdesease.org. Few parts of Pynewsleecher have survived the generations of SABnzbd in a recognizable form. Still, we wish to thank Freddy for his inspiration. The home of the Pynewsleecher project: http://www.madcowdisease.org/mcd/pynewsleecher The software does not carry any license information. SABnzbd-2.3.2/licenses/License-Python.txt0000644000000000000000000003245713217005256016352 0ustar 00000000000000A. HISTORY OF THE SOFTWARE ========================== Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands as a successor of a language called ABC. Guido remains Python's principal author, although it includes many contributions from others. In 1995, Guido continued his work on Python at the Corporation for National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) in Reston, Virginia where he released several versions of the software. In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations (now Zope Corporation, see http://www.zope.com). In 2001, the Python Software Foundation (PSF, see http://www.python.org/psf/) was formed, a non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation is a sponsoring member of the PSF. All Python releases are Open Source (see http://www.opensource.org for the Open Source Definition). Historically, most, but not all, Python releases have also been GPL-compatible; the table below summarizes the various releases. Release Derived Year Owner GPL- from compatible? (1) 0.9.0 thru 1.2 1991-1995 CWI yes 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes 1.6 1.5.2 2000 CNRI no 2.0 1.6 2000 BeOpen.com no 1.6.1 1.6 2001 CNRI yes (2) 2.1 2.0+1.6.1 2001 PSF no 2.0.1 2.0+1.6.1 2001 PSF yes 2.1.1 2.1+2.0.1 2001 PSF yes 2.2 2.1.1 2001 PSF yes 2.1.2 2.1.1 2002 PSF yes 2.1.3 2.1.2 2002 PSF yes 2.2.1 2.2 2002 PSF yes 2.2.2 2.2.1 2002 PSF yes 2.2.3 2.2.2 2003 PSF yes 2.3 2.2.2 2002-2003 PSF yes 2.3.1 2.3 2002-2003 PSF yes 2.3.2 2.3.1 2002-2003 PSF yes 2.3.3 2.3.2 2002-2003 PSF yes 2.3.4 2.3.3 2004 PSF yes 2.3.5 2.3.4 2005 PSF yes 2.4 2.3 2004 PSF yes 2.4.1 2.4 2005 PSF yes 2.4.2 2.4.1 2005 PSF yes 2.4.3 2.4.2 2006 PSF yes 2.5 2.4 2006 PSF yes 2.5.1 2.5 2007 PSF yes Footnotes: (1) GPL-compatible doesn't mean that we're distributing Python under the GPL. All Python licenses, unlike the GPL, let you distribute a modified version without making your changes open source. The GPL-compatible licenses make it possible to combine Python with other software that is released under the GPL; the others don't. (2) According to Richard Stallman, 1.6.1 is not GPL-compatible, because its license has a choice of law clause. According to CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 is "not incompatible" with the GPL. Thanks to the many outside volunteers who have worked under Guido's direction to make these releases possible. B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON =============================================================== PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -------------------------------------------- 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python. 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 ------------------------------------------- BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual or Organization ("Licensee") accessing and otherwise using this software in source or binary form and its associated documentation ("the Software"). 2. Subject to the terms and conditions of this BeOpen Python License Agreement, BeOpen hereby grants Licensee a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use the Software alone or in any derivative version, provided, however, that the BeOpen Python License is retained in the Software, alone or in any derivative version prepared by Licensee. 3. BeOpen is making the Software available to Licensee on an "AS IS" basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 5. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 6. This License Agreement shall be governed by and interpreted in all respects by the law of the State of California, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote products or services of Licensee, or any third party. As an exception, the "BeOpen Python" logos available at http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page. 7. By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions of this License Agreement. CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 --------------------------------------- 1. This LICENSE AGREEMENT is between the Corporation for National Research Initiatives, having an office at 1895 Preston White Drive, Reston, VA 20191 ("CNRI"), and the Individual or Organization ("Licensee") accessing and otherwise using Python 1.6.1 software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, CNRI hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6.1 alone or in any derivative version, provided, however, that CNRI's License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) 1995-2001 Corporation for National Research Initiatives; All Rights Reserved" are retained in Python 1.6.1 alone or in any derivative version prepared by Licensee. Alternately, in lieu of CNRI's License Agreement, Licensee may substitute the following text (omitting the quotes): "Python 1.6.1 is made available subject to the terms and conditions in CNRI's License Agreement. This Agreement together with Python 1.6.1 may be located on the Internet using the following unique, persistent identifier (known as a handle): 1895.22/1013. This Agreement may also be obtained from a proxy server on the Internet using the following URL: http://hdl.handle.net/1895.22/1013". 3. In the event Licensee prepares a derivative work that is based on or incorporates Python 1.6.1 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 1.6.1. 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. This License Agreement shall be governed by the federal intellectual property law of the United States, including without limitation the federal copyright law, and, to the extent such U.S. federal law does not apply, by the law of the Commonwealth of Virginia, excluding Virginia's conflict of law provisions. Notwithstanding the foregoing, with regard to derivative works based on Python 1.6.1 that incorporate non-separable material that was previously distributed under the GNU General Public License (GPL), the law of the Commonwealth of Virginia shall govern this License Agreement only as to issues arising under or with respect to Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between CNRI and Licensee. This License Agreement does not grant permission to use CNRI trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By clicking on the "ACCEPT" button where indicated, or by copying, installing or otherwise using Python 1.6.1, Licensee agrees to be bound by the terms and conditions of this License Agreement. ACCEPT CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 -------------------------------------------------- Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. SABnzbd-2.3.2/licenses/License-PythonParts.txt0000644000000000000000000000027113217005256017351 0ustar 00000000000000pystone.py and msgfmt.py have been copied from the Python sourcecode. They are covered by the same license as Python itself, that license is contained in the file "License_Python.txt". SABnzbd-2.3.2/licenses/License-rarfile.txt0000644000000000000000000000171013217005256016501 0ustar 00000000000000The module rarfile.py is written by Marko Kreen. Home of the module: http://grue.l-t.ee/~marko/src/rarfile/ It is covered by the following license. ------------------------------------------------------------------------- Copyright (c) 2005 Marko Kreen Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. SABnzbd-2.3.2/licenses/License-rsslib.txt0000644000000000000000000000060513217005256016355 0ustar 00000000000000The module rsslib.py is written by C. Mallory. cmallory /a t/ berserk /dot/ o r g Home of the module: http://berserk.org/rsslib/ It is covered by the following license. ----------------------------------------------------------------------------- You may freely use this code in any way you can think of. ----------------------------------------------------------------------------- SABnzbd-2.3.2/licenses/License-six.txt0000644000000000000000000000211213217005256015655 0ustar 00000000000000The module six, version 1.10.0 Copyright (c) 2010-2015 Benjamin Peterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SABnzbd-2.3.2/licenses/License-systrayicon.txt0000644000000000000000000000051613217005256017447 0ustar 00000000000000On http://www.brunningonline.net/simon/blog/archives/001835.html, the author licensed SysTrayIcon.py under a variant of the WTFPL: > Any road up, help yourself. Consider SysTrayIcon.py to be under an > "Aleister Crowley" style license - "Do what thou wilt shall be the > only law". > > Err, but don't sue me if it doesn't work. ;-) SABnzbd-2.3.2/linux/sabnzbd@.service0000644000000000000000000000116113217004754015375 0ustar 00000000000000# copy or _hard_link to # Debian: /lib/systemd/system/sabnzbd@.service # others: /usr/lib/systemd/system/sabnzbd@.service # # To start SABNzbd once for USER use: # systemctl start sabnzbd@USER.service # # To start SABNzbd on boot for USER use: # systemctl enable sabnzbd@USER.service # # Config will be placed in ~USER/.sabnzbd/ [Unit] Description=SABnzbd binary newsreader Documentation=https://sabnzbd.org/wiki/ Wants=network-online.target After=network-online.target [Service] ExecStart=/opt/sabnzbd/SABnzbd.py --logging 1 --browser 0 User=%I Type=simple Restart=on-failure [Install] WantedBy=multi-user.target SABnzbd-2.3.2/locale/da/LC_MESSAGES/SABnzbd.mo0000644000000000000000000023737113217005255016374 0ustar 00000000000000B,"S*SSSS%S#!TET^T ~TTTT TT:URUYU yUU UUUV!.V6PV-V"VVV"W6(W_W {WWW.W'W W XX5XS>XX XXXX.X"Y8+YdYyYYYY YYY Y YYZ -Z#7Z[ZrZ ZZZ*ZZ6Z([:[A[ C[M[ S[3a[ [ [ [ [[[[[\\\ %\0\ A\O\(e\\ \-\\]#)]ZM]]]^& ^ 4^)>^h^^4^^?^_!_9_ X_b_,{_,_1_5`=`B`K` ^`k`{`'``5` a'a :a FaPa ma wa aa a aa aaaa b#b'b,b =bKb$Qbvb b bb#bb bbb c'c .c:cNc _c lcyccccccd+d =dJd4gddSde e8eSeH[e e ee e ee(e.f)Bf&lf,f<f&f$g?g'Rgzgggg g h&h-7hehhh hhh h hh ii4i GiUi^iyiiii%i!i j+-j Yjzj!j*j!jk'kAk*\k"kk#kk!l#lCl\lzllll llmmm%m8mAmWmpmmAmm'm!n=n]npnynn-nnn/ng o uoo&o"o9oB pPpVpgpvp$pp p p ppp ppq q6q9qAqGRq/q q qq'qr%r =r GrRrqrovr rr ss,s1s9sOs bss sss;s-s t %t0t BtOtSt6XtGtt"t u%uE(uDnu uuWv,ivvv%v#v ww8w@Xww*w<wy2&y%Yyyy'yyyy oz zz zz%zzzzz5z .{:{H@{n{{||/|O|qb|c|H8}o}]})O~ y~~~~~~ ~~~~ ~~$,<D0L}     '8V^qv̀Ҁ  1"B e+pE L X,f‚ւ'  /)Ys; ̓׃c"k#A,*!L3c!υ!"6T%\  ˆ܆4 + 6B K*Y   ( #8L^ zӈM>Y#r%͉R܉</lq"Ê j+%ҋ-ڋ $-6 O\ mxČʌߌ  +E dp < /<KZ_ e p }ێߎ  '6Ie m z ͐ %8 K Xfm2t  Ƒ ӑߑ)0Ary Ւ  /EV]d~ʓӓ  !#E\k}FHO bo ɕܕ. ƖҖ  09#M q|,Ǘϗޗ  $4E z 33.&U)q!̚ -%,S($Ǜ!&9Ol"|&:Ɯo )y3  ",= Ub q {" ĞО '(>E. ğ/П/-0-^&&$ڠ$3$3X11 R q | ٢ ޢ:V_gv /ң ף  &@"2.5aA٦S^>= /M:+ W, >:CKQ`")!LAn ëЫEZݬ.@`hotv7ɭ/JO-ۮ// OYn-"ۯ#."Hk}$Ȱ˰ݰ !b?$ DZ:ұ #7#F"j-%˲L > HU]f ly _0 E:^/ߴ:Zcr %ʵRϵU"Mx=ƶ0!5W\ rv1ECB+̸#)F[Jm&̹&'.Vqz  ƺ˺ͺҺغ   % ?JN VbgltqDi $B4.'C*k # %- S^u %, 4>G5Y1<<F  ,7]J^ #&/Vr$" +2&)Y(    .8NT,YN?1G M[ s-& !7>E K>Vo-'%="[ ~* S k.u%" !$ F%g@4#"5(XE . '; cm V# "-JN7^.B ' 6D\d {  ($ =JZ#k6  5PY h s~" (*Sl+"ach" (( A6MA"! ,6/P'9; "-CRg.B ( ; F"T w  !& =IQew(~ ( 4BFUs | ! !;]{2c' M4 8 D R _l(q()&)=>0|'!*".<*k) &/?\ y" '4!= _*k%&--08^)).:1U*':#-Q/o!,*+E$e   %,?VsV{#'"#Aey0%9u).,8JJ% *4; KV_$qG0.>M+S l/B GQ"W@z8  '+23Ff- JFa6,Hu*!</"l+, 8%-Sk# P cq %2)@JFr& +8)WeL~yWE !* 3A"Z}1 2< K U_ gr  #: A O\ {8)*&, . $0@Th&{  * B!dsn# ;E\/+2G[c{$ ( #3GM\m=   )*<@If l'v    !,Ga~ O '*R+gY1 2 7 'W  %   !  ,   -   6  > H  _ k          "  .  < H a  "     7    5 A [ j |        ! !: MW`e x!. 7A Xe}? 8B ]jz(, 5P kw  (Ee ~ +3 S`o[JSfv | " !  3<(R {.   : D5e  3:4S)#!1%81^// ' 5)Ku "(6MlT*5 BJ drz  $ 4'U }(B3( 0 A 7U 7 5 5 ,1!,^!*!*!=!=";]";" """" ""Y#m## ####$###$ $$$/$7$P$ j$t$ |$$$$,$$$$ %"% 7%B%[%) &5& Q'/r'-'@'(`(K(BC) )d)-) &*Z0**-F+t+|+A++ ++++,,),*,G*-r-z-- --J+. v....:.$)/N/ V/`/e/%g////8//0$0!60OX00$00)0"141R1[1u1/1*11*24:2o22222223 3 3;3D3'L3jt3&3 4>4 Q4 ^4l44"4.4 44*4,'5eT5 555 55 5 5 66 #6i-636D6h71y777;7 78'8:8J8.Q88N8`8I59?9/9"9::.:?:A:E:W:7:X;Ev;.;&;-<@<[<Vp<<,< =(=*H=s=== ====== ====== =>> >>>>&>7> ;>F>J> P>]>b> ~>>> >>>>>>>> SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!
If authentication is enabled, you will need to login again.NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAdvancedAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Also test releasesAlwaysApplication TokenApplication token (required)Apply filtersApply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryCertificate verificationChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentCompact layoutComplete FolderComplete folder speedCompletedCompleted Download FolderConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCorrupt RAR fileCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecoder failure: Out of memoryDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDetect identical NZB files (based on items in your History or files in .nzb Backup Folder)Detect identical episodes in series (based on "name/season/episode" of items in your History)DeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDisable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDownloads will not unpacked.DualView1DualView2Duplicate NZBE.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Indexer IntegrationEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable notification scriptEnable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExecutes a custom scriptExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra history columnExtra queue columnExtracting...FILTEREDFail job (move to History)FailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send Windows notificationFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: Failing duplicate NZB "%s"FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File not on serverFile setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user scripts.Folder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.For unreliable servers, will be ignored longer in case of failuresForceForce DisconnectForce DownloadForcing disconnectFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom Show SxxEyyFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGenerate new self-signed certificate and key. Requires SABnzbd restart!Glitter has some (new) features you might like!Go to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHTTPS certificate verificationHelpHelp us translate SABnzbd in your language!
Add untranslated texts or improved existing translations here:Hibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIncrease performance by forcing a lower SSL encryption strength.Indexer Categories / GroupsIndexer id (%s) not found for ratings fileIndexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to "Indexer Categories / Groups" to match more categories. Use commas to separate terms. Wildcards in the terms are supported.
More information can be found on the Wiki.IndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIssuesIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job failedJob finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!Location for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLog inLog outLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMeaningMinimalMinimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateMondayMonthMoreMore thumbs down than upMovie NameMovie SortingMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelMultiPar binary... NOT found!NZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNone of the enabled servers have the 'Default' category selected. Jobs in the queue that are not assigned to one of the server's categories will not be downloaded.NormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification ScriptNotification Sent!Notification script "%s" does not existNotificationsNotifyOSDNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly external access requires loginOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPROPAGATING %s minPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.Pre-queue script marked job as failedPre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressPropagation delayProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge NZBs on the current pagePurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionPython script "%s" does not have execute (+x) permission setQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRAR files failed to verifyRAR files verified successfullyRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemember meRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRemoving jobRemoving jobsRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...Restore DefaultsResultResumeResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABYenc disabled: no correct version found! (Found v%s, expecting v%s)SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyencSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.SABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSSL CiphersSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScript returned exit code %s and output "%s"ScriptsScripts FolderSearchSeason NumberSecure (SSL) connections from SABnzbd to newsservers and HTTPS websites will be encrypted, however, validating a server's identity using its certificates is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-date local CA certificates are required.Secure connection to serverSecuritySelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeperate multiple URLs by a commaSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s uses an untrusted certificate [%s]Server %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer could not complete requestServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeed up repairs by installing multicore Par2, it is available for many platforms.SpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...StrictSubjectSubmitSubmitted. Thank you!SundaySupport the project, Donate!Suspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETabbed layout
(separate queue and history)TaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key provides identity to indexer. Check your profile on the indexer's website.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis prevents multiple repair runs by downloading all par2 files when needed.This server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying RAR-based verificationTrying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUUencode detected, only yEnc encoding is supported [%s]Unauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown SSL protocol: Try disabling SSL or connecting on a different port.Unknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unsuccessful login attempt from %sUnusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UploadingUptimeUse global interface settingsUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User logged inUser logged in to the web interfaceUser script can flag job as failedUsernameValuesVerification and repair will not be possible.Verified successfully using SFV filesVerify certificates when connecting to indexers and RSS-sources using HTTPS.VerifyingVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen the user script returns a non-zero exit code, the job will be flagged as failed.When your IP address changes or SABnzbd is restarted the session will expire.Which percentage of the linespeed should SABnzbd use, e.g. 50Which script should we execute for notification?Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou can set access rights for systems outside your local network. Requires List of local network ranges to be defined.You must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] RAR-based verification failed: %s[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2017-10-27 21:53+0000 Last-Translator: Søren Language-Team: Danish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:30+0000 X-Generator: Launchpad (build 18511) SABnzbd kan ikke finde sin webgrænseflade filer i %s.
Venligst installer programmet igen.

SABnzbd har fundet gemt data fra en anden SABnzbd version
men kan ikke genbruge dataene fra det andet program.

Du ønsker måske at afslutte din kø først med det andet program.

Efter dette, start programmet med "- rene" valgmulighede.
Dette vil slette den nu værende kø og historik!
SABnzbd læser filen "%s". SABnzbd opdagede, at filen sqlite3.dll mangler .

Nogle dårligt designet virus-scannere fjernede denne fil .
Tjek venligst din virus-scanner, du kan prøve at geninstallere SABnzbd og klage til din virus-scanner leverandør .

SABnzbd har brug for en ledig TCP / IP-port til sine interne webserver.
Port %s på %s blev forsøgt, men den er ikke til rådighed .
Nogle andre programmer bruger porten eller SABnzbd kører allerede.

Genstart venligst SABnzbd med et andet portnummer. SABnzbd har brug for en gyldig vært adresse til intern webserver .
Du har angivet en ugyldig adresse.
Sikkert valg er localhost og 0.0.0.0

Venligst genstart SABnzbd med en gyldig host adresse . SABnzbd kommer med ABSOLUT INGEN GARANTI. Det er gratis software, og du er velkommen til at videredistribuere det under visse betingelser. Den er licenseret under GNU General Public License version 2 eller (efter eget valg) enhver senere version %s -> Ukendt kodning%s => mangler fra alle servere, afviser%s artikler havde ikke-matchende dubletter%s artikler misdannede%s artikler manglede%s artikler blev fjernet%s mappe: %s adgang mislykkedes%s filer i %s%s er ikke et korrekt ciffer værdi%s er ikke en godkendt e-mail adresse%s mangler  Server løsning 
SABnzbd genstart færdig.
Vent i ca 5 sekunder og klik derefter på knappen nedenunder..

Opdater
Fejlfinding+ Info+Slette+Reparere+Udpakke.nzb Backup mappe0 er højeste prioritet, 100 er den laveste prioritet1x05 Episodemappe1x05 Sæsonmappe7ZIP sæt "%s" er ufuldstændig, kan ikke udpakke7za binary... IKKE fundet!
Hvis godkendelse er aktiveret, skal du logge ind igen.OBS: Mapper vil blive oprettet automatisk, når du gemmer. Du kan bruge absolutte stier til at gemme uden for standardmapperne.Data vil ikke blive flyttet. Kræver SABnzbd genstartet!AlderAPI (ingen konfiguration)API-nøgleAPI nøgle QR kodeForkert API-nøgle, anvend api-nøglen fra Konfiguration-> Generelt i dit tredjepartsprogram:API-nøgle mangler, indtast api-nøglen fra Konfiguration-> Generelt i dit tredjepartsprogram:API nøgle for ProwlAfbrydAfbryd hvisAfbryd job, der ikke kan færdiggøresAfbrudt, kan ikke afsluttesAfbrudt, kryptering registreretAfbrudt, rating filter matchede (%s)Afbrudt, uønsket extension fundetAcceptereAdgang nægtetUdførHåndter downloads efter filtrering regler.Aktion når uønsket extension er fundet i RAR filHandling når krypteret RAR er downloadetAktion når uønsket extension er fundetHandlingerTilføjTilføj filTilføj NZBTilføj NZB filer Opret planlægningTilføj serverTilføjet NZBAdministrativ mappeAvanceretPåvirkede KategorierAlderAlleAlle filer vil ligges ind i en enkelt mappe.Alle lokale netværksadresser starter med disse præfikser (ofte "192.168.1.")Tillad belastningsjusteringGiver mulighed for belastningsjustering med optimering for IPv6Test også udgivelserAltidProgram tokenProgram token (krævet)Anvend filtreAnvend på markeredeEr du sikker på at du vil genstarte SABnzbd?Er du sikker på du vil lukke SABnzbd?Er du sikker?ArgumenterCache størrelse af artiklerArtikel identifikatorMindstHøjstAudioLyd ratingGodkendelse mislykkedes, kontrollere brugernavn / adgangskode.Brugeroplysninger mangler, indtast brugernavn / password fra Konfiguration-> Generelt i dit tredjepartsprogram:Automatisk genoptagAuto-pause, når ledig plads kommer under denne værdi.
I bytes, evt. efterfulgt af K, M, G, T. For eksempel: '800M 'eller '8 G'Sortere automatisk efter (gennemsnits) alder.BTilbageSikkerhedskopiDårlig respons fra pushbullet (%s): %sDårlig respons fra pushover (%s): %sForkert tidsplan %s ved %s:%sForkert udformet yEnc artikel i %sBåndbreddeBloker genopfriskninger ved at hænge overBundenGennemseCPU ModelCache artikler i hukommelsen for at reducere diskadgang.
I bytes, efterfulgt af K,M,G. For eksempel: "64M" eller "128M"Cached %s artikler (%s)AnnullérDet lykkedes ikke at ændre rettigheder på %sKan ikke tilslutte til server %s [%s]Kan ikke oprette %s mappe %sKan ikke oprette backup fil for %sKan ikke oprette mappe %sKan ikke oprette endelig mappe %sKan ikke oprette temp fil for %sKan ikke finde e-mail skabeloner i %sKan ikke finde webskabeloner: %s, forsøger med standardskabelonKan ikke starte browseren, sandsynligvis ikke fundetKan ikke nå SABHelper tjenesteKan ikke læse %sKan ikke læse overvåget mappe %sKan ikke sende, mangler nødvendige dataKan ikke skrive til historik database, kontroller adgangsrettigheder!Kan ikke skrive til INI fil %sKategorierKategoriCertifikatkontrolÆndringerne er ikke gemt og vil blive mistet.Ændringer kræver genstart af SABnzbd!Tjek alleTjek før downloadKontroller for ny versionKontrollererKontrol af interval (i minutter, i hvert fald 15). Ikke aktiv, når du bruger skemaer!Vælg et Web-grænseflade udseende.Ryd listenFjernelse af %s mislykkedes.RydNulstil tællerKlik på gentagelse testknappen nedenfor for at afgøreKlik for at teste de indtastede informationer.Lukning af alle browservinduer / faneblade vil ikke lukke SABnzbd.Kommasepareret listeKommentarKompakt layoutFærdig mappeKomplet mappe hastighedFærdigFærdig download mappeKonfigurationKonfigurations filOpsætningBekræft Historik-fjernelseBekræft Kø-fjernelseBekræftetForbindelse %s@%s mislykkedes, besked %sTilslutning lykkedes!Tilslutning mislykkedes!ForbindelserBeholder BreddeØdelagt RAR filDet lykkedes ikke at tilslutte (%s)Kan ikke udpakke %sKunne ikke skrive. Kontrollér, at mappen er skrivbar.Aktuel planlægningTilpasseTDUPLIKEREDagligtDaglige mapperBeskadigede historik database, skabte tom udskiftningOversigtDato sorteringDatoformatMånedsdagÅrtiDekoder fejl: Ikke mere hukommelseAfkodning af %s mislykkedesStandardStandard Base FolderFjernSletFjern alleSlet kompletteSlet mislykketFjern efter downloadSlet alle afsluttede emner fra historie?Slet alle hentede filer?Fjern alt fra køen?Slet alle mislykkedes emner fra historiken?Fjernelse af %s mislykkedes!Find identiske downloadsOpdage identiske episoder i serierFundet identiske NZB filer (baseret på elementer i din historik eller filer i. nzb Backup mappe)Fundet identiske episoder i serie (baseret på "navn /sæson /episode" af elementer i din historik)EnhedEnhed som meddelse skal sendes tilEnhed(er)Enhed(er) som meddelelse skal sendes tilDeaktivere kvota styringDeaktiveretHTTPS fejlede på grund af manglende CERT og KEY filerKassérAfbryd fra usenet-serverne når køen er tom eller sat på pause.Afbryd når køen er tomPåmindelse når harddisk er fyldtDiskfejl ved oprettelse af fil %sDisk fuldDisken er fuld! Pauser...Udfør en ekstra kontrol baseret på SFV-filer.Har ikke gyldig godkendelse til feed %sBliver kvota nulstillet hver dag, uge ​​eller måned?Har du ingen usenet leverandør? Vi anbefaler at prøve %s.NedDownloaderOverførsel fuldførtDownload mappeDownload mislykkedesDownload alle par2 filerDownload mislykkedes - ikke på din server (e)Download mappe hastighedOverførslen kan mislykkes, kun %s af det krævede %s tilgængeligHentetHentede i %s med et gennemsnit på %sB/sDownloaderHentede filerDownloads vil ikke blive udpakket.Flerskærme1Flerskærme2Dublet NZBEks.F.eks. 8 eller 20KRYPTEREDEFEJL:FEJL: %sFEJL: CRC mislykkedes i "%s"FEJL: stien for lang (%s)FEJL: lykkedes ikke at finde "%s"FEJL: skrivefejll (%s)Tid tilbageRedigerÆndre NZB detaljerEllers pause hvisE-mailE-mail påmindelse når job er fuldførtE-mail modtagereE-mail sendereSendt E-mail!E-mail-mappe skabelonerE-mail adresse hvor den skal sendes til.E-mail afsendelse mislykkedesNødsituationTomTom NZB fil %sTom RSS post blev fundet (%s)AktivereAktivere 7zipAktivere datosorteringAktivere filtreringAktiver GrowlHTTPS AktiveringAktiver indekseringen IntegrationAktivere filmsorteringAktiver NotifyOSDAktivere Prowl notifikationAktiver Pushbullet notifikationerAktivere Pushover anmeldelserAktiver SFV-baseret kontrolAktivere TV sorteringAktivér UnzipAktiver Windows notifikationerAktiver adgang til interface fra en HTTPS-adresse.Aktiver mappe omdøbningAktiver til mindre brug af hukommelse. Deaktiver for at forhindre langsom job fra at blokerer køenAktivere notification scriptAktivere kvota styringAktivere rekursive udpakningAktiveretSlutter stien med en stjerne *, vil forhindre oprettelse af ​​job mapper.URLEpisodenavnEpisodenummerEpisode.NavnEpisode_NavnFejlFejl "%s" når du køre file_join på %sFejl "%s" mens par2_repair kørte på %sFejl "%s" når du køre rar_unpack på %sFejl "%s" når du køre unzip() på %sFejl %s når du kører par2_repair på %sFejl %s: Du skal angive et gyldigt brugernavn og adgangskode.Fejl ved oprettelse af SSL-nøgle og certifikat.Det lykkedes ikke at hente TV info (%s)Det lykkedes ikke at importere %sDownloadnings fejl %s, ødelagt fil fundetFejl ved fjernelse af %sDet lykkedes ikke at fjerne arbejdsmappen (%s)Det lykkedes ikke at omdøbe "%s" til "%s"Det lykkedes ikke at tilføje %s, sletteFejl ved lukning af systemKun ved fejlFejl: Sti længde bør være under %s.Fejl: Køen er ikke tom, kan ikke skifte mappe.Fejl: Forkert sessionsnøgleFejl: Kræver sessionsnøgleFejl/AdvarselAltEksempelUdfører et brugerdefineret scriptAfslut SABnzbdendelseEksterne internetadgangEkstra PAR2 parameterEkstra kolonne historieEkstra kø kolonneUdpakning...FILTEREDMislykkes job (flyt til historik)MislykkedesDet lykkedes ikke at logge på serveren %sOprettelse af (%s) mislykkedesDet lykkedes ikke at flytte %s til %sGodkendelse til mailserver mislykkedesDet lykkedes ikke at lukke databasen, se loggDet lykkedes ikke at lukke e-mail tilslutningDet lykkedes ikke at kompilere regex for søgestreng: %sDet lykkedes ikke at tilslutte mailserverDet lykkedes ikke systemet at gå i dvaleDet lykkedes ikke at importere %s filer fra %sDet lykkedes ikke at initialisere %s@%s med begrundelse %sDet lykkedes ikke at initialisere TLS tilslutningKunne ikke flytte filerKunne ikke omdøbe lignende fil: %s til %sDet lykkedes ikke at omdøbe: %s til %sDet lykkedes ikke at genstarte NZB efter præ-kontrol (%s)Mislykkedes at hente RSS fra %s: %sKunne ikke sende Prowl beskedDet lykkedes ikke at sende Windows notificationDet lykkedes ikke at sende e-mailDet lykkedes ikke at sende pushbullet beskedDet lykkedes ikke at sende pushover beskedDet lykkedes ikke systemet at gå i standbyKunne ikke starte web-interfaceKunne ikke starte web-grænseflade: Fejler dublet NZB "%s"MislykkedesFejl i tempfile.mkstempAlvorlig fejlFatal fejl ved lagring af stateFatal fejl i AssemblerFeedHentHent NZB fra URLHenterHenter %s block...Henter ekstra block...Fil %s er tom, springer overFiltypeFil, der indeholder alle passwords. Vil blive brugt på password beskyttede RAR filer.Filsammenlægning af %s mislykkedesFilnavn eller sti til HTTPS Certifikat.Filnavn eller sti til HTTPS kæde.Filnavn eller sti til HTTPS Nøgle.Fil ikke på serverFil sætFilnavnFilterFiltrerer prøve filer (f.eks. video eksempler).FørstMappe, der indeholder bruger-scripts.Mappe, der indeholder brugerdefinerede e-mail-skabeloner.Mappe til at gennemsøge for. Nzb filer.
Skanner også for .zip .rar og .tar.gz arkiver efter .nzb filer.Mappe/SøgestiMapperBrugernavn for e-mail som kræver godkendelse.Password for e-mail som kræver godkendelse.For servere: Kontroller navne er kompatibel med Windows.For upålidelige servere, vil blive ignoreret længere i tilfælde af fejlTvingeGennemtving afbrydelseGennemtving downloadTvinge afbrydelseFormater: .nzb, .rar, .zip, .gz, .bz2ForumLedig tempdiskpladsLedig diskpladsForekomstFredagFra Show SxxEyyFra SxxEyyFuld APIFuld webinterfaceØvrig hjælp kan du finde på voresGBGenereltGenerere Ny NøgleGenerer ny selvsigneret certifikat og nøgle. Kræver SABnzbd genstart!Glitter har nogle (nye) egenskaber, du kan lide!Gå til SABnzbdGå til guidenGrowlHTTP og HTTPS porte kan ikke være de sammeHTTPS CertifikatHTTPS kæde certifikaterHTTPS NøgleHTTPS Portverifikation HTTPS certifikatHjælpHjælp os med at oversætte SABnzbd på dit sprog!
Tilføj uoversatte tekster eller forbedrede eksisterende oversættelser her:Sæt computer i dvaleSkjul RedigeringsalternativSkjul detaljerSkjul/Vis komplette filerHøjHistorikHistorik (de 10 seneste poster)Historie ElementbegrænsningHold Skiftetasten nede for at vælge et områdeHjemStartsideVærtAdresse som SABnzbd ska lytte på.Hvor længe eller indtil hvornår du vil standse? (på engelsk!)Hvor meget der kan downloades i denne måned (K / M / G)VenterUfuldstændigIONice parametreIPv6 adresseIRCInaktivHvis tom, vil standard-porten kun lytte til HTTPS.Hvis du får denne fejlmeddelelse igen, prøv et andet portnummer.
Ignorer Sample-filerIgnorere hvilken som helst mappe indeni arkivIgnorerer identiske NZB "%s"Ligger iI tilfælde af "Pause", skal du angive en adgangskode og genoptage jobbet.I tilfælde af SABnzbd genstart vil denne skærm forsvinde automatisk!I mappeFor at hente fra usenet kræves der adgang fra en udbyder. Din internetudbyder kan give dig adgang, men en præmie udbyder anbefales.Inkompatibel feedØdelagt kø-fil fundet, kan ikke fortsætteUfuldstændig mappeUfuldstændig NZB fil %sUfuldstændig sekvens af filsammenlægningForkert RSS-feed beskrivelse "%s"Fejl parameterFejl værdi før %s: %sForkert kodet password%sØge ydeevnen ved at tvinge en lavere SSL-kryptering styrke.Indekseringen kategorier / grupperIndexer id (%s) ikke fundet for ratings filIndeksatorer kan levere en kategori inde NZB som SABnzbd vil forsøge at matche de kategorier defineret nedenfor. Derudover kan du føje betingelser til ' indekseringen kategorier / grupper til at matche flere kategorier. Brug kommaer til at adskille vilkår. Jokertegn i vilkårene er understøttet.IndekseringØdelagt NZB fil %s, springer over (årsag=%s, linje=%s)Ugyldig kodning af e-mail skabelon %sUgyldig server adresse.Ugyldige serverdetaljerForkert loggning i historiken av %sInvertereProblemerDet anbefales, at du højreklikker og bogmærker denne placering, og bruger dette bogmærke for at få adgang SABnzbd, når det kører i baggrunden.Jobbet misllykedesJob afsluttetSammenlægger filerSammenlæggerBehold løse download i ekstra mapperSprogSidsteSeneste advarslerStart web browser ved opstartStarter standard web browser når SABnzbd starter.HastighedsbegrænsningLinksVis alle uønskede extensions. For eksempel: exe or exe, comListen over filtypenavne, der skal slettes efter download. < br / > For eksempel: nfo eller nfo, sfvListe over lokale netværk intervallerIndlæser...Downloadning af %s mislykkedesIndlæsning af %s mislykkedes med fejl %sLokal IPv4 adressseLocalStorage (cookies) er deaktiveret i din browser, indstillinger for brugergrænsefladen vil gå tabt, når du lukker browseren!Placering for kø administrativ og historik database.
Kan kun ændres, når køen er tom.Placering af logfiler for SABnzbd.
Kræver genstart af SABnzbd!Sted at opbevare færdige, fuldt forarbejdede downloads.
Kan tilsidesættes af bruger-definerede kategorier.Sted at gemme uforarbejdede downloads.
Kan kun ændres, når køen er tom.Sted hvor .nzb filer gemmes.Log mappeLog inLog udLogningMistet forbindelsen til SABnzbd..LavSmå bogstaverMBGør Windows kompatibelMatchedeMax hastighedMaksimal linje hastighedMaksimalt antal forsøg per serverMaksimalt antal forsøgBetyderMinimalMinimum fri plads til midlertidige download mappeMangler sessionsnøgleMangler artiklerModeratMandagMånedMereFlere thumbs ned end opFilm NavnFilm sorteringFilm.NavnFilm_NavnFlytterFlytter...Multi-operationerMulti-del etiketteMultiPar binær... IKKE fundet!NZB nøgleNZB tilføjet i køenNavnNameserver / DNS LookupNavngivningAldrigNy version %s tilgængeligNy version tilgængligNæsteGod parameterIngen adgangIngen e-mail skabeloner fundetIngen mappeIngen efterbehandling på grund af mislykket godkendelseIngen modtagere givet, ingen e-mail sendtIngen resultaterIngen egnet godkendelsesmetode blev fundetIngenIngen af ​​de aktiverede servere har kategorien 'Standard' valgt. Job i køen som ikke er tildelt en af ​​serverens kategorier vil ikke blive downloadet.NormalMatchede ikkeIkke tilgængeligIkke nok diskplads til at fuldføre downloads.Bruges ikkeIntet er valgt!Notification CenterNotification ScriptNotifikation sendtNotification scriptet "%s" findes ikkeMeddelelserNotifyOSDSekunder mellem skanninger for .nzb filer.VALGFRIT Bruger passwordVALGFRIT konto brugernavnSlået fraGamle kø opdaget, bruge Status-> reparation for at konvertere køVed afslutningVed fejl, prøv alternativ NZBNår køen er færdigPå hvilken dag i måneden eller ugen (1 = mandag) nulstiller din internetudbyder kvota? (Valgfrit med tt: mm)Kun artiklerne fra starten af køenKun ekstern adgang kræver loginKun udføre efterbehandling af jobs som har bestået PAR2 kontrollen.Bruges kun ved Growl fjern server (vært: port)Brug kun denne server for disse kategorier.Åbn informations URLÅben et terminalvindue og tast linjen (eksempel):Åben færdig mappeValgfriValgfri Supplerende NZBValgfrit password.Valgfrit brugernavn.Valgfri adgangskode til Growl serverAngiv et valgfrit filnavnMulighederEller trække og slippe filer i vinduet!RækkefølgeOriginalfilnavnForældreløse jobsAndetAndre beskederEt andet problemUdenfor retentionPAUSETPROPAGATING %s minPar verificering mislykkedes på %s, mens QuickCheck lykkedesParameterDelnummerKodeordPassword-filKodeord maskeret med ******, forsøg igenBehov adgangskodeStiMønsterHjælp til SorteringsstrængPausePause altPause downloading under efterbehandlingPause iPause 1 timePause 15 minutterPause 3 timerPause 30 minutterPause 5 minutterPause 6 timerPause i hvor mange minutter?Pause i...Pause høj prioritets jobsPause lav prioritets jobsPause normal prioritets jobsPause efterbehandlingSat på pausePauser downloadet i begyndelsen af efterbehandling og igen når den er færdig.Pause duplikeret NZB "%s"Procentvis af linje hastighedTilladelser til fuldførte overførslerPersonlig API nøglePersonlig API nøgle for Prowl (påkrævet)Personlige notaterVær opmærksom på at 0.0.0.0 værtsnavn har brug for en IPv6-adresse for ekstern adgangAngiv detaljerne fra din primære usenet udbyder.PortPort som SABnzbd ska lytte på.Efterbehandling mislykkedes for %s (%s)EfterbehandlingEfterbehandling kun verificerede jobsEfterbehandlingEfterbehandling i gangEfterbehandling blev afbrudt (%s)Indlæg vil blive sat på pause indtil de har mindst denne alder. Indstilling af job prioritet til Tvang vil springe forsinkelsen over.Før-kø script job markeret som mislykkedetFør kø bruger scriptForudindstillingerTryk Startkey + R og skriv linjen (eksempel):ForegåendeForhindre belastningsjusteringForrigePrioritetSandsynligt delt kontoProblem medForarbejdede resultatForløbProgrammet startede ikke!FremgangPropagation delayProwlOffentlig IPv4 adresseRydRens komplette NZB'erRens mislykket NZB'erRens mislykket NZB'er & slet filerTøm historikRens NZB'erRens NZB'er & slet filerRens NZBs på den aktuelle sideRens køenVil du virkelig tømme historiken?Tøm køen?PushbulletPushoverPython-versionPython script '%s' har ikke udfør (+x) tilladelsessætKøKø (de første 10 poster)Kø færdigKøen elementbegrænsningKø reparationHurtig kontrol...Hurtig kontrollerendeAfslutKvotaKvota tilbageKvota periodeKvote brugt, pause downloadingRRAR filer kunne ikke bekræfteRAR filer kontrolleres med succesRSSRSS Opdaterings intervalRSS Feed %s er tomKørte %sIntervalSjældent anvendte indstillinger. Deres betydning og forklaring, klik på knappen Hjælp for at gå til siden Wiki.
Ændre ikke disse uden at kontrollere wiki'en først, da disse kan give alvorlige side følger.
Standardværdierne er mellem parenteserne.Læs alle Feeds nuLæs FeedLæs RSS feedsLæs alle RSS feedsLæs mere om dette på Wiki Help!OpdatereOpdateringsintervalOpdateringsfrekvensAfviseRelative mapper er baseret påTilbageværendeHusk migFjern NZBFjern NZB & slet filerFjern serverFjern alle valgte filerFjern fuldførte jobFjern mislykkede jobsFjernelse af%s mislykkedesFjernelse af jobFjernelse af jobsOmdøbeReparérReparation mislykkedes, ikke nok reparation blokke (%s mangler)ReparererReparation mislykkedes, %sReparerer...Gentagelse testErstat mellemrum i mappenavnErstat punktummer i mappenavnErstat punktum med mellemrum i mappenavnErstat mellemrum med understreg i mappenavn.RapportérKræverKræver en Prowl kontoKæver en Pushbullet kontoKræver en Pushover kontoKræver CatNulstilNulstil kvota nuNulstil dagGenstartGenstart SABnzbdGenstart uden loginGenstarter SABnzbd...Gendan standardværdierResultatGenoptagGenoptag høj prioritets jobsGenoptag lav prioritets jobsGenoptag normal prioritets jobsGenoptag efterbehandlingGenoptagerTilgængelighed i dageForsøg igenPrøv igen allePrøv igen allePrøv igen alle mislykkedePrøv igen alle mislykkede jobPrøv igen alle mislykkede job i historien?Prøv igen alle mislykkede job?Køre scriptKør script...Kør bruger script %sS01E05 EpisodemappeS01E05 SæsonmappeSABYenc deaktiveret: Der blev ikke fundet nogen korrekt version (Fandt v%s, forventede v%s)SABYenc modul... IKKE fundet! Forventede v%s - https://sabnzbd.org/sabyencSABnzbd %s startetSABnzbd AdresseSABnzbd passwordSABnzbd PortSABnzbd Hurtigstart’s GuideSABnzbd brugernavnSABnzbd versionSABnzbd WebserverSABnzbd fandt en alvorlig fejl:SABnzbd lukning udført.SABnzbd blev startet med kodning %s, dette bør være UTF-8. Forvent problemer med Unicoded fil- og mappenavne i downloads.SABnzbd vil nu køre i baggrunden.SMTP-serverSQL Kommando mislykkedes, se loggSSLSSL-chifreLørdagGemGem ændringerGemtGemmes %s mislykkedesGemmer..Scan overvåget mappeTidsplan for ikke-eksisterende server %sPlanlægningscriptScript exit kode er %sScript returnerede exit kode %s og output "%s"ScriptsScripts mappeSøgSæsonnummerSikker (SSL) forbindelser fra SABnzbd til nyhedsserverne og HTTPS hjemmesider vil blive krypteret, dog validering af en servers identitet ved hjælp af sine certifikater er ikke mulig. Python 2.7.9 eller derover, OpenSSL 1.0.2 eller derover og op-to-date kræves lokale CA certifikater.Sikker forbindelse til serverSikkerhedVælg et web-grænseflade sprog.Vælg kun hvis din udbyder tillader SSL-forbindelser.UdvælgelseSendSend gruppeSend RSS meddelelserSend tilbage til køenSend e-mail når en RSS-feed tilføjer job i køen.Send e-mail når harddisken er fyldt og SABnzbd er pauset.Send gruppe kommandoen, før du anmoder om artikler.Send meddelelser til GrowlSend notifications to Notification CenterSend meddelelser til NotifyOSDSendt %s til køAdskil flere URL-adresser med kommaSerie sorteringServerServer %s kræver brugernavn/passwordServer %s bruger et upålideligt HTTPS-certifikatServer %s bruger et upålidelig certifikat [%s]Server %s vil blive ignoreret for i %s minutterServerdetaljerServeradresseServeradressen "%s:%s" er ikke gyldigt.Kræver serveradresseServeren kunne ikke fuldføre anmodningenServerbeskrivelseServer belastningsjusteringServernavnet løser ikkeServerkodeordServer afslut under login-sekvens.Serveren kræver brugernavn og password.Server fejl (server kode %s); kunne ikke få %s på %sServerAngive tilladelses mønster for afsluttede filer.
Anvend ciffer. For eksempel: "755" eller "777"Indtast ISP's server for udgående e-mail.Installationen er nu fuldført!Skal download genoptages efter kvotaen er nulstillet?Vis AltVis RedigeringsalternativVis mislykketVis logVis navnVis Navn på mappeVis aktive forbindelserVis detaljerVis grænsefladeVis.NavnVis_NavnViser %s til %s af %s resultatViser et resultatLuk nedLuk computerAfslut SABnzbdPåbegynder lukning af SABnzbd..Signal %s modtaget, gemmer og lukker...StørrelseSome files failed to verify against "%s"Nogle servere levere en alternativ NZB når et download mislykkes.Vi kunne desværre ikke fortolke denne. Prøv igen.SortereSorteringsstrengSortere efter alderSortere efter Alder (Nyeste→Ældst)Sortere efter Alder (Ældst→Nyeste)Sortere efter alder Nyeste→ÆldstSortere efter alder Ældst→NyesteSortere efter Navn (A→Z)Sortere efter Navn (Z→A)Sortere efter navn A→ZSortere efter navn Z→ASortere efter Størrelse (Størst→Mindst)Sortere efter Størrelse (Mindst→Størst)Sortere efter størrelse Størst→MindstSortere efter størrelse Mindst→StørstSorteringKildeSpamSpecielHastighedHastighedsbegrænsningFremskynde reparationer ved at installere multicopy Par2, det findes til mange platforme.HastighedsbegrænsningSæt computer i standbyStart guideStarter reparationStart / LukningStatusStatus og grænseflade indstillingerStopStandserStrengEmneTilføjTilføjet. Mange tak!SøndagStøt projektet, donér!Suspect fejl i downloaderParameterSysloadSystemmapperSystem Performance (Pystone)TEKSTFOR STORTabbed layout
(separat kø og historie)OpgaveMidlertidig mappeMidlertidig download mappeTest E-mailAfprøv notifikationTestserverTester serverdetaljer..."Reparation" knappen vil genstarte SABnzbd og lave en komplet
rekonstruktion af køens indhold, bevare allerede downloadede filer.
Dette vil ændre køens orden.Det automatiske usenet download værktøjAfkrydsningsfeltet ud for feed navn skal afkrydses for at feeds vil være aktiveret og automatisk kontrolleres for nye emner.
Når et feed er tilføjet, vil det kun hente nye informationer og ikke noget, der allerede findes i RSS-feed, medmindre du trykker på "Force Download".Værtsnavnet er ikke indstillet.Antallet af forbindelser tilladt af din udbyderServeren svarede ikke korrekt til helo hilsenDer er ingen forbindelser angivet. Angiv mindst én forbindelse.Der er forældreløse jobs i download mappen.
Du kan vælge at slette dem (herunder filer) eller sende dem tilbage til køen.Denne nøgle indeholder identitet indekseringen. Tjek din profil på indekseringens hjemmeside.Denne nøgle vil give 3. parts programmer til at tilføje NZBs til SABnzbd.Denne nøgle vil give 3. parts programmer fuld adgang til SABnzbd.Denne månedDette forhindrer flere reparationer kører ved at downloade alle par2 filer når det er nødvendigt.Denne server tillader ikke SSL på denne portDenne ugeDette vil forhindre indhold i at blive opdateret når musens markør kører hen over køenKnappen vil genstarte SABnzbd..
Andvend den hvis du oplever stabilitets problem.
Downlodning vil blive sat på pause før genstart og genoptages automatisk igen efter genstart.Dette vil sende en test E-mail til din konto.TorsdagTimeoutTimeout: Forsøg at aktivere SSL eller tilslut via en anden port.Resterende tidTidsudløbTitelTitel nøgleordTo: %s From: %s Date: %s Subject: SABnzbd rapportere Disk Fuld Hej, SABnzbd er stoppet med at downloade, fordi disken er næsten fuld. Vær venlig at give plads og genoptage SABnzbd manuelt. I dagVis/Skjul Tilføj NZBFor lidt diskplads tvinger system i PAUSEAlt for mange forbindelser til serveren %sAlt for mange forbindelser, pause en download eller forsøg igen senereØverstTopmenuTotaltFejlfindingPrøv vores nye hud Glitter! Frisk nyt design, der er optimeret til stationære og mobile enheder. Gå til Config - > Generelt for at ændre din hud.Prøv at forudsige en vellykket afslutning, før selve download (langsom!)Forsøger 7zip med password "%s"Forsøger RAR-baseret kontrolForsøger SFV verifikationForsøger at hente NZB fra %sForsøger at sætte status på ikke eksisterende server %sForsøger unrar med adgangskode "%s"TirsdagJusteringTypePUNC søgning "%s" er ikke tilladt herUønsketURL hentning mislykkedes; %sURLGRABBER CRASHEDUUENCODE detekteret, kun yEnc kodning understøttes [%s]Uautoriseret adgangOphæv blokeringUdefineret serverUkendt fejl under afkodning af %sUkendt SSL protokol: Prøv at deaktivere SSL eller forbinder på en anden port.Ukendt handling: %sUkendt godkendelsesfejl i mailserverUdpakUdpakke arkiver (rar, zip, 7z) i arkiver.Udpakning af nesting for dybt [%s]Udpakket %s filer/mapper i %sUdpakkerUdpakning mislykkedes, %sUdpakning mislykkedes, CRC-fejlUdpakning mislykkedes, arkivet kræver passwordUdpakningen mislykkedes, stien er for langUdpakning mislykkedes, se loggUdpakning mislykkedes, kunne ikke finde %sUdpakning mislykkedes, skrivefejl eller disken fuld?Mislykkede login forsøg fra %sFejl, Ubrugelig arkivfilUbrugelig RAR filUønsket extension i rar fil %sUønsket extensionOpOpdatering tilgængeligUploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UploaderOppetidBrug globale grænseflade indstillingerBrug midlertidig navne under efterbehandling. Deaktiver når dit system ikke kan håndtere det ordentligt.Brugt før, en NZB kommer ind i køen.Brugt chaceNyttigt, hvis en newsserver har mere end én IPv4/IPv6-adresseBrugermapperBruger nøgleBruger nøgle (krævet)Bruger logget indBruger logget på webgrænsefladenBruger-script kan markere et job som mislykketBrugernavnVærdierVerificering og reperation er ikke muligt.Kontrolleret korrekt ved hjælp af SFV filerKontroller certifikater, når du opretter forbindelse til indeksører og RSS-kilder ved hjælp HTTPS.BekræfterBekræftelse...UdgaveMeget lavVideoVideo ratingVis scriptlogVirus/spamVENT %s sekunderADVARSEL:Advarsel: Afbrudt job '%s' på grund af krypterede RAR fil (hvis oplyst, alle adgangskoder blev forsøgt)ADVARSEL: Afbrudt job "%s" på grund af rating (%s)Advarsel: I "%s" uønsket extension i RAR fil. Uønsket fil er "%s" Advarsel: Pauset job '%s' på grund af krypterede RAR fil (hvis oplyst, alle adgangskoder blev forsøgt)ADVARSEL: Pause job "%s" på grund af rating (%s)VenterAdvarselAdvarsel: Localhost er tvetydig, bruge numerisk IP-adresse.AdvarslerOvervåget MappeSkannings interval for overvåget mappeWebgrænsefladeOnsdagKontroller for ny version af SABnzbd hver uge.NårNår under download det bliver klart, at for meget data mangler, afbryd jobbetNår bruger scriptet returnerer et non-zero exit code, vil jobbet blive markeret som mislykkedesNår din IP-adresse ændres eller SABnzbd genstarter, udløber sessionen.Hvilken procentdel af linje hastighed bør SABnzbd bruge, fx 50Hvilke script skal vi udføre for notification?Hvem skal vi sige sendte e-mailen?WikiWindows NotifikationerSkrive hastighedXÅrÅr-Måned mapperDu kan angive adgangsrettigheder for systemer uden for dit lokale netværk. Kræver liste over lokale netværks intervaller, skal defineres.Du skal aktivere JavaScript for at få Plush til virke!Du skal angive den maksimale båndbredde, før du kan angive en båndbredde begrænsningDin Unrar version er %s, vi anbefaler version %s eller højere.
Din personlige Pushbullet API nøgle (krævet)[%s] Fejl "%s" under filsammenlægning[%s] Fejl "%s" under udpakning af RAR fil(er)[%s] Sammen lagte %s filer[%s] Ingen par2 sæt[%s] PAR2 modtog forkerte indstillinger, tjek din konfiguration->Skifter indstillinger[%s] Hurtig kontrol OK[%s] RAR-baserede kontrollen mislykkedes: %s[%s] Repareret i %s[%s] Bekræftelse i %s, alle filer er ok[%s] Bekræftelse i %s, kræver reparation_yenc modul... IKKE fundet!artiklerlydsag-justeretSletddagdagedeaktivere serverdownvotedaktivere serverfilhtimetimernøgleordtilbagemmanueltminutmin.minutterikke installeretfraslået frapåellereller mindresidepar2 binær... IKKE fundet!passwordedsekundsekunderse logfilspamtekstUkendtunrar binær... IKKE fundet!unzip binær... IKKE fundet!videougeSABnzbd-2.3.2/locale/de/LC_MESSAGES/SABnzbd.mo0000644000000000000000000026644413217005255016403 0ustar 00000000000000q#,Go-GdGI I KKL*L')MQMlMM MMMM NN1NNNNNNN1 ObZbb]bc&"c Ic)Sc }c(ccc4c d?dSdmdd dd,d,d!e1@e5reeee eee'e&f5iOijiiii ii4i1jSFjjjjjHj 9k CkPk _k lkyk(k.k)k&l,(l<Ul&lll'lm!m=mYm ym m&m-mmn3n BnMnUn nn {nnnnn nnnoo0oCo%Zo!oo+o op!*p*Lp!wpp'pp*p"q?q#\qq!qqqqr/rJrRr nrzrrrrrrrrrs)sA8szs's!ssstt t-'tUt[t/{tgt uu&'u"Nu9quBuuuvv$'vLv Rv ^v ivsvzv vvv vvvvGv/8w hw vww'www w wwxox xx xxxxxxx y3y 8yByGy;fy-y9y z zz ,z9z=z6BzyzGzD{"S{v{{E{D{ |+||,|}}%,}#R}v}}}@}~*"~<M~ 2%GFm̀' H; 1 <I}N ׂ̂߂ *%"%Hnw|5 ܃Hn7Ä˄݄qcHo/]) '29AIf jux $0ψaKRX] v  lj؉  %=DJf|  1" +KP ,BK]q' Ό،/+EM;Q cǍ"+#NAr,* 3#Wlu!!"ӏ%BH Zhn }4  * DOT \h n(x ё  :G`y’Mɒ2#Ko%R<EJ"i̔j%o- (5 FQhq ʖ  =I\ mx<͗ӗ $38 > I VwyΘ "> F S`g  Κ $ 1?F2M  ՛)0KR[t  Мڜ/6=WqƝ՝ ۝ !8O^pFHB Ub sϟ . Š   #,#@ dov,¡ѡ ء  48 mw |33.H)d!  -",P(}$ĥ!#6Li"y&:æo)v3   ): R_ n x" ͨ ި'(>B. /ͩ/---[&&$ת$3!3U11 R n y ֬ ۬7S\ds /ϭ׭ ܭ  +E"235fAްSc>= 4M?+ Wò, >?HPVe".!QAsµ ȵյE_Ķ.Eemty{7ηah|J-B/Iy չ-6"Vy#." $-Rfi{ ݻb$V {: μ׼#"AJ-Q%L  "+ 1> N Ye_n0ξE^E/Կܿ:(7 Q _%iRwU_M=0A!r v1NEB +#)  J2}&&'6? ESY[_d s }   ',19Snty'80`;3(!J]1x $! ,   1Pe@y N*U)/HWngjA [e;t-'.05 fr#97$"GPbt  :NQ,#5Sf{*&   )4:IMPy/Fr++,I h*s ^ $ ,:5 p,+'53HO|^++W0t0N!% G Rn\HC-2q" Z"*} 0:/Ej (vF  *" ;-F#t 4D(m}=  % 2<(En 2(O,xH$*wOn67= u0, E ^ih+&+%Q-a;( JC`  ?OLoF $. N Y dqw %,*D] al83-a~ !*Lg#|($%-%>9d"dK ) 9 GU0\;1,2(M[9,6/f3))& 23BPv$)'-)6`pw 0*'9a)1L-*LX:&078(p"<):#/^&5!+ )9-c'($)+@l)2 5ZA!*$*9 T _i5p 8 ;:K?^ $5 A Vbj z 3 b:c2 " 3>]c$$ 6 &H o t %|   B     ( /0 >` = @  ' 6  G T X :a  M* x )   K E-  s ~ 7FO8%%<ZVz- U;a*n7R/l BfIL (2/>O5:8RRXv*"M]-vCeJ~!Pr     '0Hy 4<qo % BL \ fp&" 0 5 @J No  :3 E 1V   C!J![!8l!!!!!!,"B" U"_"2h"""""Z" ;#,G# t#n#>#-.$h\$=$1%5%EL%%%% %$%)&#B&f&2o& &&&&&&' %'0'PC' ' '' '8'' (((*( 3(/A( q((((((()()(1)!Z),|)+)) )T)&M*'t***#**j +>t++/+*+,)#,M,],&w,,Y=-!--B- ../. 7.&B. i.u. ~.. ...... /)*/T/ c/q/$//// //080 P0,^00&00011 #1.1G14[11*1!1111 22.!2P3 g3r33!3 333 33 44 54B4\4$m4"4"44 4 5 5 5O)5 y5555#552 67<6t6 |66"6 66 6 7)7 ;7G7Z7r7!77 7)7"7-8,B8o8 88888 8$879,T999"999R:JX:: :: ::;;&;18;j;;".< Q<A]<<<< << << ==)7=a=i=p=1== ===.=? 8?+C?;o??? ??%?L@H[@9@"@4A&6A&]A"A AAA5ABBEIB(BBB%BB*CECXC"nCC"C3C5C.Di5D+D&DPD CE#QEuEE EEEEE F F5#FYFuF}FFF3FF7F[&G;G GGG8G8'H8`H8H+H+H+*I+VI;I<I;I<7J tJJJJJJjJ)K!DKfKzKKKKKKKKKK L6LHLeL nL yLLLL4LLLL M %M3MMM%aMM.eNN"O6O5 PM@PP`-QUQNQ 3Rd@R.R RlRMS%T =THTM\T TTTTTUU.U"'V^JVV VV VV^mWW$WX(,XBUX$XXXXX$X Y" Y0Y;GYkYY Z Z%#ZMIZZ7Z Z8Z$(["M[ p[z[$[8[N[*D\5o\1\F\!]@]V](l]] ]] ] ]"] ^^.-^#\^n^I^9_BK_____$_8 ` D`Q`0W`+`Q` aa)aBa JaWa]ala a aaa=1bJobb7Cc{ccLc cc'cd-dG6d~dOddq`eZeO-fB}f#fffggg"g4g<g^hG_hh#Di0hi/iiiYj'Zj6jj0j1j1kMkUk)[kkkkkkkkkkkkkkll lll l2l6l:l=l BlOl"Ulxllllll l#l#lmm SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!
If authentication is enabled, you will need to login again.NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAdvancedAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Allow proper releasesAlso test releasesAlwaysApplication TokenApplication token (required)Apply filtersApply to SelectedAprilAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAugustAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically delete completed jobs from History. Beware that Duplicate Detection and some external tools rely on History information.Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseBypass series duplicate detection if PROPER, REAL or REPACK is detected in the download nameCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryCertificate hostname mismatch: the server hostname is not listed in the certificate. This is a server issue.Certificate not valid. This is most probably a server issue.Certificate verificationChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking extra filesChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentCompact layoutComplete FolderComplete folder speedCompletedCompleted Download FolderCompleted Download Folder %s is on FAT file system, limiting maximum file size to 4GBConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCorrupt RAR fileCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecemberDecoder failure: Out of memoryDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDetect identical NZB files (based on items in your History or files in .nzb Backup Folder)Detect identical episodes in series (based on "name/season/episode" of items in your History)DeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDirect UnpackDirect Unpack was automatically enabled.Disable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDo not keep any completed jobsDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDownloads will not unpacked.DualView1DualView2Duplicate NZBE.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: File too large for filesystem (%s)ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Indexer IntegrationEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable notification scriptEnable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExecutes a custom scriptExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra history columnExtra queue columnExtracting...FILTEREDFail job (move to History)FailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send Windows notificationFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: Failing duplicate NZB "%s"FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFebruaryFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File not on serverFile setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user scripts.Folder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.For unreliable servers, will be ignored longer in case of failuresForceForce DisconnectForce DownloadForcing disconnectFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom Show SxxEyyFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGenerate new self-signed certificate and key. Requires SABnzbd restart!Glitter has some (new) features you might like!Go to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHTTPS certificate verificationHelpHelp us translate SABnzbd in your language!
Add untranslated texts or improved existing translations here:Hibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory RetentionHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)How often (in seconds) the same notification will be sentIDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If the SABnzbd Host or Port is exposed to the internet, your current settings allow full external access to the SABnzbd interface.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIncrease performance by forcing a lower SSL encryption strength.Indexer Categories / GroupsIndexer id (%s) not found for ratings fileIndexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to "Indexer Categories / Groups" to match more categories. Use commas to separate terms. Wildcards in the terms are supported.
More information can be found on the Wiki.Indexers can supply rating information when a job is added and SABnzbd can report to the indexer if a job couldn't be completed.IndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid par2 files or invalid PAR2 parameters, cannot verify or repairInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIssuesIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.JanuaryJob "%s" is probably encrypted due to RAR with same name inside this RARJob "%s" is probably encrypted: "password" in filename "%s"Job failedJob finishedJobsJobs will start unpacking during the downloading to reduce post-processing time. Only works for jobs that do not need repair.Join filesJoiningJulyJuneKeep all jobsKeep completed jobs maximum number of daysKeep loose downloads in extra foldersKeep maximum number of completed jobsLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!Location for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLog inLog outLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMarchMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMayMeaningMinimalMinimal: when SSL is enabled, verify the identity of the server using its certificates. Strict: verify and enforce matching hostname.Minimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateModule subprocessww missing. Expect problems with Unicoded file and directory names in downloads.MondayMonthMoreMore thumbs down than upMovie NameMovie SortingMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelMultiPar binary... NOT found!Multicore Par2NZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNone of the enabled servers have the 'Default' category selected. Jobs in the queue that are not assigned to one of the server's categories will not be downloaded.NormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification ScriptNotification Sent!Notification script "%s" does not existNotificationsNotifyOSDNovemberNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOctoberOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly external access requires loginOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPROPAGATING %s minPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause jobs with categoryPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.Pre-queue script marked job as failedPre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressPropagation delayProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge NZBs on the current pagePurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionPython script "%s" does not have execute (+x) permission setQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRAR files failed to verifyRAR files verified successfullyRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemember meRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRemoving jobRemoving jobsRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...Restore DefaultsResultResumeResume high prioirty jobsResume jobs with categoryResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABYenc disabled: no correct version found! (Found v%s, expecting v%s)SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyencSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.SABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSSL CiphersSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScript returned exit code %s and output "%s"ScriptsScripts FolderSearchSeason NumberSecure (SSL) connections from SABnzbd to newsservers and HTTPS websites will be encrypted, however, validating a server's identity using its certificates is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-date local CA certificates are required.Secure connection to serverSecuritySelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeperate multiple URLs by a commaSeptemberSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s uses an untrusted certificate [%s]Server %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer could not complete requestServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeed up repairs by installing multicore Par2, it is available for many platforms.SpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...StrictSubjectSubmitSubmitted. Thank you!SundaySupport the project, Donate!Suspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETabbed layout
(separate queue and history)Tag jobTaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key provides identity to indexer. Check your profile on the indexer's website.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis prevents multiple repair runs by downloading all par2 files when needed.This server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying RAR-based verificationTrying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUUencode detected, only yEnc encoding is supported [%s]Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running.Unauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown SSL protocol: Try disabling SSL or connecting on a different port.Unknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, file too large for filesystem (FAT?)Unpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unsuccessful login attempt from %sUnusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UploadingUptimeUse global interface settingsUse tags from indexerUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User logged inUser logged in to the web interfaceUser script can flag job as failedUsernameValuesVerification and repair will not be possible.Verified successfully using SFV filesVerify certificates when connecting to indexers and RSS-sources using HTTPS.VerifyingVerifying repairVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen sorting, use tags from indexer for title, season, episode, etc. Otherwise all naming is derived from the NZB name.When the user script returns a non-zero exit code, the job will be flagged as failed.When your IP address changes or SABnzbd is restarted the session will expire.Which percentage of the linespeed should SABnzbd use, e.g. 50Which script should we execute for notification?Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou can set access rights for systems outside your local network. Requires List of local network ranges to be defined.You must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your password file contains more than 30 passwords, testing all these passwords takes a lot of time. Try to only list useful passwords.Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] RAR-based verification failed: %s[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2017-10-10 19:03+0000 Last-Translator: Robin Munkittrick Language-Team: German MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:30+0000 X-Generator: Launchpad (build 18511) SABnzbd kann die Dateien für die Web-Oberfläche in %s nicht finden.
Installieren Sie bitte das Programm erneut.

SABnzbd hat die gespeicherten Daten einer anderen SABnzbd-Version erkannt,
kann diese aber nicht wiederverwenden.

Es wird empfohlen, die ausstehenden Downloads mit der anderen Version fertigzustellen.

Starten Sie dieses Programm danach mit der "--clean"-Option.
Dies löscht die Download-Warteschlange und den Download-Verlauf!
SABnzbd hat die Datei "%s" gelesen. SABnzbd hat erkannt, dass die Datei sqlite3.dll fehlt.

Manche unausgereiften Viren-Scanner löschen diese Datei.
Bitte überprüfen Sie den Viren-Scanner, versuchen Sie eine Neuinstallation von SABnzbd und beschweren Sie sich beim Hersteller des Viren-Scanners.

Für seinen internen Web-Server benötigt SABnzbd einen freien TCP/IP-Port.
Port %s auf %s wurde probiert, ist aber nicht verfügbar.
Entweder verwendet eine andere Software den Port oder SABnzbd läuft bereits.

Starten Sie SABnzbd bitte mit einer anderen Portnummer neu. Für seinen internen Web-Server benötigt SABnzbd eine gültige Rechner-Adresse.
Sie haben eine ungültige Adresse angegeben.
Sichere Werte sind localhost und 0.0.0.0

Starten Sie SABnzbd bitte mit einer gültigen Rechner-Adresse neu. Für SABnzbd besteht KEINERLEI GARANTIE. SABnzbd ist freie Software, die Sie unter bestimmten Bedingungen weitergeben dürfen. Sie steht unter der GNU GENERAL PUBLIC LICENSE Version 2 oder (nach Ihrer Option) jeder späteren Version. %s -> Unbekannte Kodierung%s wurde auf keinem Server gefunden und daher übersprungen%s Artikel hatten nicht übereinstimmende Duplikate%s Artikel hatten ein ungültiges Format%s Artikel fehlten%s Artikel wurden entferntZugriff auf das Verzeichnis %s fehlgeschlagen: %s%s Dateien in %s%s ist kein gültiger Oktal-Wert%s ist keine gültige E-Mail-Adresse%s fehlt Adresse wird aufgelöst … 
SABnzbd wurde beendet.
Warten Sie 5 Sekunden und klicken Sie danach auf folgenden Knopf.

Aktualisieren
+ Fehlersuche+ Info+Löschen+Reparieren+EntpackenNZB-Backup-Ordner0 ist die höchste, 100 die niedrigste Priorität1x05 Episoden-Ordner1x05 Staffel-OrdnerDas 7zip-Set "%s" ist unvollständig, kann nicht entpackt werden7za-Programmdatei nicht gefunden
Wenn Anmeldung aktiviert ist, müssen sie sich danach noch mal anmelden.HINWEIS: Ordner werden beim Speichern automatisch erstellt. Sie können absolute Pfade angeben, um Ordner ausserhalb der standardmässigen Ordner zu verwenden.Es werden keine Dateien entfernt. Benötigt einen Neustart von SABnzbd!AlterAPI (kein Einstellungen)API-SchlüsselAPI-Key OR-CodeAPI-Schlüssel ungültig. Bitte API-Schlüssel aus Einstellungen->Allgemein in die externe Anwendung eingeben:API-Schlüssel fehlt. Bitte API-Schlüssel aus Einstellungen->Allgemein in die externe Anwendung eingeben:API-Schlüssel für ProwlAbbrechenAbbrechen wennAufträge abbrechen, die nicht abgeschlossen werden könnenAbgebrochen, kann nicht fertiggestellt werdenAbgebrochen, Verschlüsselung vorhandenAbbruch, Bewertungsfilter stimmt überein (%s)Abgebrochen, unerwünschte Dateieindung gefundenAkzeptierenZugriff verweigertAktionAction-Downloads nach Filterregeln.Aktion bei ungewollter Dateiendung innerhalb RAR-ArchivenAktion wenn eine verschlüsselte RAR Datei geladen wirdAktion bei ungewollter DateienendungAktionenHinzufügen einerDatei hinzufügenNZB hinzufügenNZB Dateien hinzufügen Regel hinzufügenServer hinzufügenHinzugefügte NZBAdministrativer OrdnerErweitertBetroffene KategorienAlterAlleAlle Dateien werden in einen einzelnen Ordner gespeichert.Alle lokalen Netzwerkadressen starten mit diesen Präfixen (oft "192.168.1.1")Lastverteilung zulassenLastverteilung mit IPv6-Optimierung zulassenErlaube "Proper" ReleasesAuch Test-VeröffentlichungenImmerApplikationstokenApplikationstoken (benötigt)Filter übernehmenAuf Auswahl anwendenAprilMöchten Sie SABnzbd wirklich neu starten?Möchten Sie SABnzbd wirklich beenden?Sind Sie sicher?ArgumenteBegrenzung des Artikel-CachesArtikelbezeichnerMindestensHöchstensAudioAudiobewertungAugustAuthentifizierung fehlgeschlagen. Überprüfen Sie Benutzername und Passwort.Authentifizierung fehlt. Bitte Benutzernamen und Passwort aus Einstellungen->Allgemein in die externe Anwendung eingeben:Automatisch fortsetzenSABnzbd hält automatisch an, wenn der freie Speicherplatz unter diesen Wert fällt.
In Bytes, gefolgt von einem optionalen K, M oder G. Zum Beispiel: "800M" or "8G"Fertige Aufträge automatisch aus dem Verlauf entfernen. Duplikatserkennung und manche externe Skripte benötigen Informationen aus dem Verlauf.Einträge automatisch nach ihrem (durchschnittlichen) Alter sortieren.BZurückSicherheitskopieFehlerhafte Antwort von Pushbullet (%s): %sFehlerhafte Antwort von Pushbullet (%s): %sUngültige Regel %s um %s:%sUngültiger yEnc-Artikel in %sBandbreiteAktualisierung durch Mauszeiger verhindernGanz nach untenDurchsuchenUmgehe Serien Duplikat-Erkennung, wenn PROPER, REAL oder REPACK im Download-Namen erkannt wirdCPU-ModellArtikel werden zwischengespeichert, um die Anzahl der Zugriffe auf die Festplatte zu reduzieren.
In Bytes, gefolgt von einem optionalen K, M oder G. Zum Beispiel: "64M" oder "128M"%s Artikel im Cache (%s)AbbrechenRechte von %s konnten nicht geändert werdenVerbindung zum Server %s kann nicht hergestellt werden. %sKann kein %s Ordner %s erstellenKann keine Sicherungsdatei erstellen für %sVerzeichnis %s konnte nicht angelegt werdenKonnte Download-Ordner %s nicht anlegenTemporäre Datei für %s konnte nicht angelegt werdenIn %s konnten keine E-Mail-Vorlagen gefunden werdenKonnte Web-Vorlage nicht finden: %s Versuche die Standard-Vorlage zu verwenden.Der Standard-Browser konnte nicht gestartet werden, da er wahrscheinlich nicht gefunden wurde.SABHelper-Dienst kann nicht erreicht werden%s kann nicht gelesen werdenÜberwachter Ordner %s kann nicht gelesen werdenAbsenden nicht möglich, benötigte Daten fehlenKann nicht in die Verlaufsdatenbank schreiben, überprüfe die Zugriffsrechte!Kann INI-Datei %s nicht schreibenKategorienKategorieZertifikat ungültig: Der Server-Host ist nicht im angegeben Zertifikat enthalten. Dies ist ein Serverproblem.Zertifikat ist nicht gültig. Dies ist wahrscheinlich ein Serverproblem.Zertifikat überprüfungDie Änderungen wurden nicht gespeichert und werden verloren gehen.Änderungen benötigen einen Neustart von SABnzbd!Alle auswählenVor dem Herunterladen überprüfenAuf neue Version prüfenWird überprüftÜberprüfe zusätzliche DateienÜberprüfungs-Intervall (in Minuten, mindestens 15). Nicht aktive wenn Regeln aktiv sind!Gestaltung der Web-Oberfläche verändern.Unerwünschte DateienAufräumen von %s fehlgeschlagenLöschenZähler zurücksetzenKlick auf "Test wiederholen" um es festzustellenKlicken um die eingegebenen Informationen zu überprüfen.Das Schliessen des Browser-Fensters oder -Tabs beendet SABnzbd NICHT.Durch Komma getrennte ListeKommentarKompaktes LayoutFertige DownloadsZielverzeichnis GeschwindigkeitFertiggestelltOrdner für fertige DownloadsDownload-Ordner %s für abgeschlossene Downloads auf FAT Dateisystem, ist auf maximale Dateigröße von 4GB begrenzt.EinstellungenKonfigurationsdateiEinstellungenLöschen von Verlaufeinträgen bestätigenLöschen von Downloads bestätigenBestätigtFehler beim Verbinden mit %s@%s, Meldung = %sVerbindung erfolgreich hergestellt!Verbindung fehlgeschlagen!VerbindungenBreiteDefekte RAR DateiDie Verbindung konnte nicht überprüft werden. (%s)Konnte nicht entpacken %sKonnte nicht schreiben. Überprüfe, ob der Ordner beschreibbar ist.Aktuelle RegelnBenutzerdefiniertLDUPLIKATTäglichTägliche OrdnerVerlaufsdatenbank geschädigt, eine leere neue wurde erstelltÜbersichtsseiteSortieren nach DatumDatumsformatTag im MonatJahrzehntDezemberDecoder Fehler: Nicht genügend SpeicherFehler beim Dekodieren von %s.StandardStandardmässiger Basis-OrdnerLöschenLöschenAlle löschenFertige entfernenFehlgeschlagene entfernenNach dem Download löschenAlle fertigen Downloads aus dem Verlauf entfernen?Alle heruntergeladenen Dateien löschen?Alle Elemente in der Warteschlange löschen?Möchten Sie alle fehlergeschlagenen Downloads aus dem Verlauf löschen?Löschen von %s fehlgeschlagen!Doppelte Downloads erkennenDoppelte Episoden in Serien erkennenDoppelte NZB Datei entdeckt (basierend auf den Eintragungen in der Historie oder den .nzb Dateien im NZB-Backup-Ordner)Identische Episoden in den Serien entdeckt (basierend auf "name/season/episode") der Einträge in der HistorieGerätGeräte, welche die Benachrichtigungen empfangen sollenGerät(e)Geräte, welche die Nachrichten empfangen sollenDirekt entpackenDirekt entpacken wurde automatisch aktiviertQuoten-Management ausschaltenDeaktiviertHTTPS wegen fehlenden Zertifikats- und Schlüsseldateien deaktiviert.VerwerfenVerbindung zu Usenet-Servern trennen,
wenn die Warteschlange leer ist oder SABnzbd angehalten wurde.Bei leerer Warteschlange Verbindung trennenBenachrichtigung bei voller FestplatteFestplattenfehler beim Anlegen der Datei %sFestplatte vollFestplatte voll! Downloads werden angehalten.Zusätzliche Überprüfung mittels SFV-Dateien durchführenKeine gültige Berechtigung für Feed %sFertige Aufträge nicht behaltenWird das Kontingent jeden Tag, jede Woche oder jeden Monat zurückgesetzt?Wenn Sie noch keinen Usenet-Provider haben, empfehlen wir Ihnen %s.Nach untenHerunterladenDownload fertigDownloadsDownload FehlgeschlagenAlle Par2-Dateien herunterladenDownload fehlgeschlagen - Nicht auf deinem/n Server/n vorhandenZielverzeichnis GeschwindigkeitDownload wahrscheinlich fehlgeschlagen, nur %s von benötigten %s verfügbarHeruntergeladenHeruntergeladen in %s mit einer Durchschnittsgeschwindigkeit von %sB/sAm herunterladenDownloadsDownloads werden nicht enpackt.DualView 1DualView 2Doppelte NZBZ. B.Z.B. 8 oder 20VERSCHLÜSSELTFEHLER:FEHLER: %sFEHLER: CRC in »%s« fehlgeschlagen.Fehler: Datei zu groß für Dateisystem (%s)FEHLER: Pfad ist zu lang (%s)FEHLER: »%s« kann nicht gefunden werden.FEHLER: Schreibfehler %sETABearbeitenNZB-Details bearbeitenAndererseits pausieren wennE-MailEmail-Benachrichtigung beim Fertigstellen von AufträgenE-Mail-EmpfängerE-Mail-AbsenderE-Mail gesendet!Ordner mit E-Mail-VorlagenE-Mail-Adresse, an die die E-Mails gesendet werden.E-Mail erfolgreich versendetNotfallLeerLeere NZB-Datei %sLeerer RSS-Feed gefunden: %sAktivieren7zip aktivierenSortieren nach Datum aktivierenFilter aktivierenGrowl aktivierenHTTPS aktivierenIndexer Integration eingeschaltetFilm-Sortierung aktivierenNotifyOSD aktivierenProwl-Benachrichtigungen aktivierenPushbullet-Benachrichtigungen aktivierenPushover-Benachrichtungen aktivierenSFV-basierte Überprüfung aktivierenTV-Sortierung aktivierenunzip aktivierenWindows-Benachrichtigungen aktivierenZugriff auf die Oberfläche über HTTPS-Adressen erlaubenOrdner-Umbenennung aktivierenFür geringere Speicher-Verwendung aktivieren.
Deaktivieren, um zu verhindern, dass langsame Aufträge
die anderen Einträge in der Warteschlange blockieren.Aktiviere Benachrichtigungs-SkriptQuoten-Management einschaltenRekursives Entpacken aktivierenAktivEin Sternchen * am Pfad-Ende verhindert die Erzeugung von Auftrags-Ordnern.URLEpisoden-NameEpisoden-NummerEpisoden.NameEpisoden_NameFehlerFehler "%s" beim Ausführen von file_join auf %sFehler "%s" beim Ausführen von par2_repair auf dem Satz %sFehler "%s" beim Ausführen von rar_unpack auf %sFehler "%s" beim Ausführen von unzip auf %sFehler "%s" beim Ausführen von par2_repair auf %sFehler %s: Sie müssen einen gültigen Benutzername und ein Passwort angeben.Fehler beim Anlegen des SSL-Schlüssels und -Zertifikats.Fehler beim Abrufen der TV-Informationen: %sFehler beim Importieren von %sFehler beim Laden von %s. Beschädigte Datei gefunden.Fehler beim Entfernen von %sFehler beim Entfernen des Arbeitsverzeichnisses %s.Fehler beim Umbenennen von "%s" nach "%s"Fehler beim Hinzufügen von %s. Entferne.Fehler beim Herunterfahren des SystemsNur bei FehlernFehler: Dateipfadlänge sollte kürzer als %s sein.Fehler: Ordner kann nicht geändert werden, da die Warteschlange nicht leer ist.Fehler: Sitzungsschlüssel ungültigFehler: Sitzungsschlüssel wird benötigtFehler/WarnungenAllesBeispielFührt ein benutzerdefiniertes Skript ausSABnzbd beendenEndungExterner InternetzugriffZusätzliche PAR2-ParameterExtra Verlauf-SpalteExtra Warteschlangen-SpalteWird entpackt …GEFILTERTAufgabe abgebrochen (verschoben in die Historie)FehlgeschlagenAnmelden beim Server fehlgeschlagen. %sErstellen von %s fehlgeschlagenVerschieben von %s nach %s fehlgeschlagenAuthentifizierung beim Mail-Server fehlgeschlagenFehler beim Schliessen der Datenbank. Beachten Sie das Nachrichtenprotokoll.Schliessen der Mail-Verbindung fehlgeschlagenKompilieren des regulären Ausdrucks für den Suchbegriff %s fehlgeschlagen.Verbindung zum Mail-Server konnte nicht hergestellt werdenFehler beim Wechsel in den RuhezustandImportieren von %s Dateien von %s fehlgeschlagenFehler %s@%s zu initialisieren, aus folgendem Grund: %sAufbau der TLS-Verbindung fehlgeschlagenDateien verschieben fehlgeschlagenUmbenennen der gleichen Datei von %s nach %s fehlgeschlagen.Umbenennen von %s nach %s fehlgeschlagen.NZB konnte nach Vorab-Check nicht neugestartet werden (%s)Abrufen des RSS-Feeds von %s fehlgeschlagen: %sKonnte Prowl-Nachricht nicht versendenWindows Benachrichtigung konnte nicht gesendet werdenSenden des E-Mails fehlgeschlagenKonnte Pushbullet-Nachricht nicht versendenKonnte Pushover-Nachricht nicht versendenFehler beim Wechsel in den BereitschaftsmodusFehler beim Starten der Weboberfläche.Fehler beim Starten der Web-Oberfläche kopieren der NZB "%s" fehlgeschlagenFehlerFehler in tempfile.mkstempSchwerwiegender FehlerSchwerer Fehler beim Speichern des ZustandsSchwerer Fehler im AssemblerFebruarFeedAbrufenNZB aus URL ladenAbrufen%s Blöcke werden abgerufen …Zusätzliche Blöcke werden abgerufen …Die Datei %s ist leer und wird daher übersprungenDateiendungDatei mit allen Passwörtern, die bei verschlüsselten RAR-Dateien probiert werden sollen.Fehler beim Zusammenfügen von %sDateiname oder Pfad des HTTPS-Zertifikats.Dateiname oder Pfad zur HTTPS-Kette.Dateiname oder Pfad des HTTPS-Schlüssels.Datei nicht auf dem ServerDateimengeDateinameFilterBeispieldateien herausfiltern (z.B. Videoausschnitte)AnfangOrdner enthält Benutzer SkripteOrdner, der benutzerdefinierte E-Mail-Vorlagen enthält.Ordner, der auf neue NZB-Dateien überwacht werden soll.
Erkennt auch ZIP-, RAR- und TAR.GZ-Archive mit NZB-Dateien.Ordner/PfadOrdnerFür authentifizierte E-Mails wird der Kontoname benötigt.Für authentifizierte E-Mails wird das Passwort benötigt.Für Server: stell sicher, dass die Dateinamen mit Windows kompatibel sind.Für unzuverlässige Server, wird bei Fehlern länger ignoriertErzwingenVerbindung trennenDownload erzwingenErzwinge TrennungFormate: .nzb, .rar, .zip, .gz, .bz2ForumFreier Speicherplatz (Ordner mit temporären Dateien)Freier SpeicherplatzHäufigkeitFreitagVon Show SxxEyyVon SxxEyyGanze APIVolles WebinterfaceWeiterführende Informationen finden Sie in unseremGBAllgemeinNeuen Schlüssel generierenNeues selbstzertifiziertes Zertifikat und Schlüssel generieren. SABnzbd muss neugestartet werden!Glitter hat ein paar (neue) Feature die du bestimmt magst!SABnzbd anzeigenAssistent öffnenGrowlHTTP und HTTPS Ports dürfen nicht Identisch sein!HTTPS-ZertifikatHTTPS-Kette ZertifikatHTTPS-SchlüsselHTTPS-PortHTTPS Zertifikat ÜberprüfungHilfeHilf uns beim Übersetzen von SABnzbd in deiner Sprache!
Neue Übersetzungen hinzufügen oder bestehende verbessern kannst du hier:Rechner in den Ruhezustand versetzenBearbeitungs-Einstellungen verbergenDetails verbergenVollendete Dateien anzeigen/versteckenHochVerlaufVerlauf mit den letzten 10 EinträgenVerlaufsgrößeLimit der Objekte im VerlaufShift-Taste gedrückt halten, um einen ganzen Bereich auszuwählenStartseiteStartseiteAdresseHost, auf dem SABnzbd auf Anfragen warten soll.Wie lange oder bis wann möchtest du pausieren? (in Englisch!)Wie viel kann in diesem Monat heruntergeladen werden (K/M/G)?Wie oft die selbe benachrichtigung (in Sekunden) geschickt wird.LEERLAUFUNVOLLSTÄNDIGIONice-ParameterIPv6-AdresseIRCLeerlaufWenn leer, hört der Standard-Port nur auf HTTPS-Anfragen.Wenn der SABnzbd Host oder Port im Netz freigegeben ist, lassen die gegenwärtigen Einstellung vollen zugriff auf die SABnzbd Oberfläche zu.Wenn Sie diesen Fehler wieder erhalten, probieren Sie eine andere Nummer.
Beispieldateien ignorierenAlle Ordner innerhalb Archiven ignorierenDoppelte NZB "%s" wird ignoriertInIm Fall von "Pause" müssen Sie ein Kennwort setzen und den Job fortsetzen.Wenn SABnzbd neustartet, wird diese Anzeige automatisch verschwinden!In OrdnernUm aus dem Usenet herunterladen zu können, benötigen Sie Zugriff auf einen Usenet-Provider. Ihr ISP bieten dies möglicherweise an, jedoch werden kostenpflichtige Provider empfohlen.Inkompatibeler RSS-FeedInkompatible Warteschlangen-Datei gefunden. Fortsetzen nicht möglich.Unfertige DownloadUnvollständige NZB-Datei %sUnvollständiger Ablauf beim zusammenführen von DateienUngültige RSS-Feed-Beschreibung "%s"Fehlerhafter ParameterFehlerhafter Wert für %s: %sUngültig kodiertes Passwort %sDie Performanz verbessern, indem eine schwächere SSL-Verschlüsselung erzwungen wird.Indexer Kategorien/GruppenIndexer ID (%s) für Bewertung nicht gefundenIndexer können eine Kategorie innerhalb des NZB liefern, welche SABnzbd versuchen wird, mit den unten definierten Kategorien entsprechen. Darüber hinaus kannst du Begriffe zu "Indexer Kategorien / Gruppen" hinzufügen, um mehreren Kategorien zu entsprechen. Verwende Kommas, um Begriffe zu trennen. Wildcards in den Begriffen werden unterstützt.
Weitere Informationen können im Wiki gefunden werden.Indexer können Rating Informationen liefern, wenn ein Job hinzugefügt wird und SABnzbd kann dem Indexer melden, wenn ein Job nicht abgeschlossen werden konnte.IndexierungUngültige NZB-Datei %s wird übersprungen: %s auf Zeile %sUngültige Kodierung der E-Mail-Vorlage %sUngültige par2-Dateien oder ungültige PAR2-Parameter, Auftrag konnte nicht überprüft oder repariert werdenUngültige Server-Adresse.Ungültige Server-AngabenUngültiges Stufen-Protokoll im Verlauf für %sInvertierenProblemeEs ist empfehlenswert, diese Seite mit einem Lesezeichen zu versehen und dieses verwenden, um SABnzbd aufzurufen, wenn es im Hintergrund läuft.JanuarAufgabe "%s" ist wahrscheinlich verschlüsselt, RAR hat den gleichen Namen wie das gepackte RAR-ArchivAufgabe "%s" ist wahrscheinlich verschlüsselt: "Passwort" im Dateiname "%s"Auftrag fehlgeschlagenAuftrag ausgeführtAufträgeAufträge werden bereits während des Download-Vorgangs entpackt, um die Nachbearbeitungszeit zu verkürzen. Nur für Aufträge, die nicht repariert werden müssen.Dateien zusammenfügenZusammenfügenJuliJuniAlle Aufträge behaltenBehalte abgeschlossene Aufträge maximal X TageUnbestimmte Downloads in einem zusätzlichen Ordner speichern.Behalte maximale Anzahl an abgeschlossenen AufträgenSpracheEndeNeuste WarnungenBrowser beim Start öffnenDen Standard-Browser öffnen, wenn SABnzbd gestartet wird.Geschwindigkeit begrenzenLinksListe aller ungewollter Dateiendungen. Zum Beispiel: exe or exe, comListe der Dateiendungen, die nach dem Download gelöscht werden sollen.
Zum Beispiel:nfo or nfo,sfvListe der lokalen NetzwerkadressenbereicheWird geladen...Fehler beim Laden von %sLaden von %s ist mit Fehler %s fehlgeschlagenLokale IPv4-AdresseLokale Speicherung (cookies) sind in ihrem Browser Deaktiviert, Oberflächen Einstellungen gehen Verloren wenn sie den Browser schließen.Ordner, der die für die Warteschlange und den Verlauf verwendeten Datenbanken enthält.
Kann nur geändert werden, wenn die Warteschlange leer ist.Hier werden Protokoll-Dateien von SABnzbd abgelegt.
Benötigt einen Neustart von SABnzbd!Hier werden fertige, verarbeitete Downloads abgelegt.
Kann von benutzerdefinierten Kategorien ausser Kraft gesetzt werden.Hier werden noch nicht verarbeitete Downloads abgelegt.
Kann nur geändert werden wenn die Warteschlange leer ist.Hier werden NZB-Dateien abgelegt.Protokoll-OrdnerAnmeldenAbmeldenProtokollVerbindung zu SABnzbd verloren..GeringKleinschreibungMBFür Windows kompatibel machenMärzEntsprichtMaximale
GeschwindigkeitMaximale DownloadgeschwindigkeitMaximale Anzahl wiederholter Versuche pro ServerMaximale WiederholungenMaiBedeutungMinimumMinimum: Wenn SSL aktiviert, prüft die Serveridentität und Benutzung seiner Zertifikate. Strikt: Prüft und stelle sicher das der Hostname stimmt.Minimaler freier Speicherplatz im temporären OrdnerSitzungs-Schlüssel fehltFehlende ArtikelMittelModul subprocessww fehlt. Fehler mit Unikodierter Datei und Verzeichnisnamen in den Downloads sind zu erwarten.MontagMonatMehrMehr Daumen-Hoch als -RunterFilm NameFilm SortierungFilm.NameFilm_NameVerschiebevorgangWird verschoben …Mehrfach-FunktionenMarkierung für mehrere TeileMultiPar Programmdatei nicht gefunden!Multicore Par2NZB-SchlüsselNZB zur Warteschlange hinzugefügtNameDNS-ServerBenennungNieNeue Version %s verfügbar unterNeue Version verfügbarWeiterNice-ParameterKein ZugriffKeine E-Mail-Vorlagen gefundenKeine OrdnerKeine Nachbearbeitung wegen fehlgeschlagener ÜberprüfungKeine E-Mail gesendet da keine Empfänger angegebenKeine ErgebnisseKeine passende Authentifizierungsmethode gefundenNichtsKeiner der aktivierten Server hat die "Standard" Kategorie ausgewählt. Jobs in der Warteschlange die nicht mit einer Server Kategorie verbunden sind werden nicht Heruntergeladen.NormalEntspricht nichtNicht verfügbarNicht genug freier Speicherplatz für fertige Downloads!Nicht verwendetNichts ausgewählt!BenachrichtigungscenterBenachrichtigungs-SkriptBenachrichtigung gesendet!Benachrichtigungsskript "%s" existiert nichtBenachrichtigungenNotifyOSDNovemberAnzahl der Sekunden zwischen zwei Überprüfungen.Optionales Konto-PasswortOptionaler Konto-BenutzernameOktoberNeinAlte Warteschlangen-Version erkannt, über Status->Reparieren ins neue Format konvertierenWenn fertigNach einem Fehler ein alternatives NZB ladenWenn fertigAn welchem Tag des Monats oder der Woche (1=Montag) setzt Ihr ISP das Kontingent zurück (optional mit hh:mm)?Nur Artikel für obersten Warteschlangen-Eintrag herunterladenNur externer Zugriff benötigt eine AnmeldungDie Nachbearbeitung nur für Aufträge durchführen,
die alle PAR2-Überprüfungen bestanden haben.Nur für entfernten Growl-Server verwenden (Rechnername:Port)Diesen Server nur für diese Kategorien benutzen.Open Informational-URLÖffnen Sie ein Terminal und geben Sie folgende Zeile ein (Beispiel):Öffne ZielverzeichnisOptionalOptionale ergänzende NZB-DateiOptionale Anmeldung mit PasswortOptionale Anmeldung mit BenutzernameOptionales Passwort für den Growl-ServerWahlweise einen Dateinamen angeben:OptionenOder Dateien per Drag-und-Drop ins Fenster ziehen!ReihenfolgeUrsprünglicher DateinameVerwaiste AufträgeAndereAndere NachrichtenAnderes ProblemAußerhalb der ServerretentionANGEHALTENAUSBREITUNG %s minPar-Verifikation für "%s" fehlgeschlagen, obwohl der QuickCheck erfolgreich warParameterTeilnummerPasswortPasswortdateiPasswort ist als ****** maskiert. Bitte erneut eingeben.passwortgeschütztPfadMusterMuster-SchlüsselAnhaltenAlle anhaltenDownloads während der Nachbearbeitung anhaltenAnhalten fürEine Stunde anhalten15 Minuten anhalten3 Stunden anhalten30 Minuten anhalten5 Minuten anhalten6 Stunden anhaltenWie viele Minuten angehalten werden soll.Anhalten für …Aufträge mit hoher Priorität pausierenAufträge mit Kategorie pausierenAufträge mit niedriger Priorität pausierenAufträge mit normaler Priorität pausierenNachbearbeiten anhaltenAngehaltenHält die Downloads zu Beginn der Nachbearbeitung an
und setzt sie danach fort.Doppelt vorhandene NZB "%s" angehaltenProzentsatz der DownloadgeschwindigkeitRechte für fertige DownloadsPersönlicher API-KeyDein API-Key für Prowl (benötigt)Persönliche NotizenBitte beachten Sie, dass der 0.0.0.0-Hostname eine IPv6-Adresse benötigen wird für den externen Zugriff.Geben Sie bitte die Informationen zu Ihrem Usenet-Provider an.PortPort, auf dem SABnzbd auf Anfragen warten soll.Nachbearbeitung von %s fehlgeschlagen (%s)NachbearbeitungNur überprüfte Aufträge nachbearbeitenNachbearbeitungNachbearbeitung gestartetNachbearbeitung wurde abgebrochen (%s)Artikel werden angehalten bis sie mindestens das gewählte alter erreicht haben. Ändern der Job Priorität auf Erzwingen wird die Verzögerung überspringen.Das Vorwarteschlangen (pre-queue) Skript hat die Downloadaufgabe als gescheitert markiertBenutzer-Skript vor WarteschlangeVoreinstellungenDrücken Sie Start+R und geben Sie folgenden Zeile ein (Beispiel):ZurückLastverteilung verhindernZurückPrioritätMöglicherweise wird das Konto geteiltProblem mitErgebnisVerarbeitenProgramm wurde nicht gestartet!FortschrittAusbreitungsverzögerungProwlÖffentliche IPv4-AdresseLeerenFertige NZBs löschenFehlgeschlagene NZBs löschenFehlgeschlagene NZBs und Dateien löschenVerlauf leerenNZBs löschenNZBs und Dateien löschenLösche NZBs auf der aktuellen SeiteWarteschlange leerenVerlauf wirklich leeren?Warteschlange leeren?PushbulletPushoverPython VersionDem Pythonskript "%s" fehlen die Ausführungsrechte (+x)WarteschlangeWarteschlange mit den 10 obersten EinträgenWarteschlange abgearbeitetLimit der Objekte in der WarteschlangeReparatur der WarteschlangeSchnelle Überprüfung …Schnelle ÜberprüfungBeendenKontingentVerbleibendes KontingentKontingents-PeriodeKontingent aufgebraucht, Downloads werden angehaltenRRAR-Datei konnten nicht überprüft werdenRAR-Datei erfolgreich überprüftRSSRSS-ÜberprüfungRSS-Feed %s war leer%s ausgeführtBereichSelten genutzte Funktionen. Bedeutung und Erklärungen finden Sie per klick auf den Hilfe-Button um auf die Wiki-Seite zu gelangen.
Änder nichts ohne vorher das Wiki gelesen zu haben, da sonst schwerwiegende Nebeneffekte auftreten können.
Die Ursprungswerte stehen zwischen den runden Klammern.Jetzt alle Feeds lesenFeed lesenRSS-Feeds lesenAlle RSS-Feeds lesenLesen Sie dazu die Hilfe im Wiki!Neu ladenAktualisierungsrateAktualisierungsrateVerwerfenRelative Ordner basieren aufVerbleibendAutomatische AnmeldungNZB löschenNZBs und Dateien löschenServer entfernenAlle ausgewählten Dateien entfernenAbgeschlossene Aufträge entfernenEntferne fehlgeschlagene AufträgeEntfernen von %s fehlgeschlagenEntferne JobEntferne JobsUmbenennenReparierenReparatur fehlgeschlagen. Nicht genug Reparatur-Blöcke vorhanden (%s zu wenig)ReparierenReparatur fehlgeschlagen. %sWird repariert …Test wiederholenLeerzeichen in Ordnernamen ersetzenPunkte in Ordner-Namen ersetzenPunkte in Ordner-Namen durch Leerzeichen ersetzen.Leerzeichen in Ordnernamen durch Unterstriche ersetzen.BerichtBenötigtBenötigt einen Prowl-AccountBenötigt einen Pushbullet-AccountBenötigt einen Pushover-AccountBenötigt KategorieZurücksetzenKontingent jetzt zurücksetzenTag zurücksetzenNeu startenSABnzbd neustartenNeustart ohne AnmeldungSABnzbd wird neu gestartet …Werkseinstellung wiederherstellenResultatFortsetzenAufträge mit hoher Priorität fortsetzenAufträge mit Kategorie fortsetzenAufträge mit niedriger Priorität fortsetzenAufträge mit normaler Priorität fortsetzenNachbearbeiten fortsetzenFortgesetztRückhaltezeitErneut versuchenAlle neustartenAlle wiederholenAlle fehlgeschlagenen neustartenFehlgeschlagene Aufträge neustartenAlle fehlgeschlagenen Aufträge im Verlauf wiederholen?Alle fehlgeschlagenen Aufträge wiederholen?Ausführen des SkriptsSkripts wird ausgeführt …Ausführen des Benutzer-Skripts %sS01E05 Episoden-OrdnerS01E05 Staffel-OrdnerSABYenc deaktiviert: Keine korrekte Version gefunden! (Gefunden v%s, Erwartet v%s)SABYenc Modul... Nicht gefunden! Erwarte v%s - https://sabnzbd.org/sabyencSABnzbd %s gestartetSABnzbd-HostSABnzbd-PasswortSABnzbd-PortSABnzbd-EinrichtungsassistentSABnzbd-BenutzernameSABnzbd-VersionSABnzbd-WebserverSABnzbd hat einen schwerwiegenden Fehler erkannt:SABnzbd wurde beendetSABnzbd wurde mit Encoder/Zeichensatz %s gestartet, Dieser sollte UTF-8 sein. Es werden Probleme mit Unicode codierten Dateien und Ordnerbezeichnungen in Downloads erwartet.SABnzbd läuft nun im Hintergrund.SMTP-ServerSQL-Befehl fehlgeschlagen. Beachten Sie das Nachrichtenprotokoll.SSLSSL-VerschlüsselungSamstagSpeichernÄnderungen speichernGespeichertFehler beim Speichern von %sSpeichervorgang …Überwachter Ordner lesenRegel für nicht existierenden Server %s.PlanungSkriptExit-Code des Skripts ist %sSkript gab Fehlercode %s und Ausgabe "%s" zurückSkripteSkript OrdnerSuchenStaffel-NummerSichere (SSL) Verbindungen von SABnzbd zu den Newsservern und HTTPS-Webseiten werden verschlüsselt, allerdings ist es nicht möglich die Identität eines Servers mittels Zertifikat zu bestätigen. Python 2.7.9 oder höher, OpenSSL 1.0.2 oder höher und aktuelle lokale CA certificate werden benötigt.Sichere Verbindung zum ServerSicherheitWählen Sie die Sprache der Weboberfläche.Nur auswählen, wenn der Provider SSL-Verbindungen erlaubt.AuswahlAbsendenGruppe sendenRSS-Benachrichtigungen sendenZurück in die Warteschlange schickenE-Mail senden, wenn ein RSS-Feed einen Auftrag zur Warteschlange hinzufügt.E-Mail senden, wenn die Festplatte voll ist und SABnzbd angehalten wird.Gruppen-Befehl senden, bevor Artikeln angefordert werden.Benachrichtigungen an Growl sendenBenachrichtigung an Benachrichtigungscenter schickenBenachrichtigungen an NotifyOSD senden%s wurde an die Warteschlange gesendetTrenne verschiedene URLs mit KommaSeptemberSortieren von TV-SerienServerServer %s benötigt ein Benutzername und ein PasswortDer Server %s nutzt ein nicht vertrauenswürdiges HTTPS-ZertifikatDer Server %s verwendet ein nicht vertrauenswürdiges Zertifikat [%s]Server %s wird für %s Minuten ignoriertServer-DetailsServer-AdresseServer-Adresse "%s:%s" ist ungültig.Server-Adresse wird benötigtServer konnte nicht vollständig antwortenServerbeschreibungServer LastverteilungKonnte Servernamen nicht auflösenServer-PasswortSever beendet beim Anmeldeverlauf.Server benötigt ein Benutzername und ein Passwort.Server-Fehler (Code %s); konnte %s von %s nicht ladenServerRechte für Dateien und Ordner festlegen.
In oktaler Notation. Zum Beispiel: "755" oder "777"ISP-Server für ausgehende E-Mails angeben.Die Einrichtung ist nun abgeschlossen.Soll wieder Heruntergeladen werden, nachdem das Kontingent zurückgesetzt wurde?Alle anzeigenBearbeitungs-Einstellungen anzeigenNur FehlgeschlageneProtokoll anzeigenSendungs NameOrdner mit Name der SendungAktive Verbindungen anzeigenDetails anzeigenInterface anzeigenSendungs.NameSendungs_NameEinträge %s bis %s von insgesamt %s werden angezeigtEin Resultat wird angezeigtBeendenRechner ausschaltenSABnzbd beendenWird beendet …Signal %s erkannt. Wird gespeichert und beendet …GrösseÜberprüfung einiger Dateien mittels %s fehlgeschlagenManche Server stellen ein alternatives NZB zur Verfügung, falls ein Download fehlschlägt.Sorry, damit konnten wir nichts anfangen. Versuchs nochmal.SortierenSortieranweisungNach Alter sortierenSortieren nach Alter Neuste→ÄltesteSortieren nach Alter Älteste→NeusteSortieren nach Alter Neuste→ÄltesteSortieren nach Alter Älteste→NeusteSortieren nach Name A→ZSortieren nach Name Z→ASortieren nach Name A→ZSortieren nach Name Z→ASortieren nach Grösse Grösste→KleisteSortieren nach Grösse Kleinste→GrössteSortieren nach Grösse Grösste→KleisteSortieren nach Grösse Kleinste→GrössteSortierungQuelleSpamSpezialGeschwindigkeitGeschwindigkeitsbegrenzungErhöhe Reparaturgeschwindigkeit durch installation von Multicore Par2, verfügbar auf vielen Plattformen.GeschwindigkeitsbegrenzungRechner in Bereitschaft versetzenAssistenten startenBeginn der ReparaturStarten/BeendenStatusStatus und Interface-OptionenAnhaltenWird angehalten …StriktBetreffSendenVersendet. Danke!SonntagBitte unterstützen Sie das Projekt durch eine Spende!Vermute Fehler im DownloaderSchalterSystemlastSystem-OrdnerSystem PerformanceTEXTZU GROSSTab Layout
(separate Warteschlange und Verlauf)Markiere AuftragAufgabeTemporärer OrdnerTemporärer Download-OrdnerE-Mail testenBenachrichtigungen testenServer überprüfenServer-Angaben werden überprüft …Ein Klick auf den Knopf "Reparieren" startet SABnzbd neu
und baut die Warteschlange neu auf, wobei bereits
heruntergeladene Dateien bestehen bleiben. Die Reihenfolge
der Warteschlange wird dabei verändert.Automatisiertes Programm für Usenet-DownloadsAktivieren Sie das Feld neben dem Feed-Namen, wenn automatisch auf neue Einträge geprüft werden soll.
Wenn ein Feed hinzugefügt wird, werden nur neue Einträge verarbeitet und nicht diejenigen, die bereits im RSS-Feed enthalten waren, ausser Sie klicken "Download erzwingen".Der Hostname wurde nicht angegebenDie Anzahl der Verbindungen, die der Provider erlaubt.Keine korrekte Server-Antwort auf den HELO/EHLO-CheckKeine Verbindungen angegeben. Bitte geben Sie mindestens eine Verbindung ein.Der Download-Ordner enthält verwaiste Aufträge.
Diese können gelöscht (zusammen mit den Dateien) oder zurück in die Warteschlange verschoben werden.Der Schlüssel liefert die Identität des Indexers. Prüfe dein Profil auf der indexer Webseite.Dieser Schlüssel erlaubt Drittprogrammen das Hinzufügen von NZB-Dateien zu SABnzbd.Dieser Schlüssel gibt Drittprogrammen uneingeschränkten Zugriff auf SABnzbd.Dieser MonatDies verhindert mehrfache Reparaturversuche, durch herunterladen aller par2 Dateien, wenn notwendig.Dieser Server erlaubt kein SSL auf diesem PortDiese WocheVerhindert, dass die Inhalte aktualisiert werden, wenn sich der Mauszeiger über der Warteschlange befindet.Ein Klick auf den Knopf \"Neu starten\" startet SABnzbd neu.
Benutzen Sie ihn, falls ein Stabilitätsproblem vorliegt.
Die Downloads werden vor dem Neustart angehalten und danach fortgesetzt.Sendet eine Test-E-Mail an Ihr Konto.DonnerstagZeitüberschreitungZeitüberschreitung: Versuchen Sie, SSL oder einen anderen Port zu verwenden.VerbleibendZeitüberschreitungTitelTitel-SchlüsselwörterTo: %s From: %s Date: %s Subject: SABnzbd meldet eine volle Festplatte Hallo, SABnzbd hat mit dem Herunterladen aufgehört, da die Festplatte fast voll " ist. Bitte geben Sie manuell Speicherplatz frei und setzen Sie die Downloads " danach fort. HeuteNZB hinzufügenAngehalten wegen zu wenig freiem SpeicherplatzZu viele Verbindungen zu Server %sZu viele Verbindungen. Bitte halten Sie die Downloads an oder versuchen Sie es später erneut.Ganz nach obenHauptmenüGesamtFehler suchenProbier' den neuen Skin Glitter! Er bietet ein frisches, für PC und Mobilgeräte optimiertes Erlebnis. Einstellen über Konfiguration -> Allgemein.Versuche die erfolgreiche Fertigstellung noch vor dem Herunterladen vorherzusagen (langsamer!)Versuche 7zip mit Passwort "%s"RAR-basierte Überprüfung versuchenVersuche SFV-ÜberprüfungNZB-Datei wird versucht von %s abzurufenStatus für nicht vorhandenen Server wird versucht %s einzustellenVersuche entpacken mit Passwort "%s"DienstagFeinabstimmungTypEUNC-Pfad "%s" ist hier nicht erlaubtUNERWÜNSCHTAbrufen der URL fehlgeschlagen; %sURLGRABBER abgestürztUUencode gefunden, nur yEnc Codierung wir unterstützt [%s]Konnte nicht an Port %s auf %s starten. Eine andere Software nutzt diesen Port oder SABnzbd läuft bereits.Unerlaubter ZugriffFreigebenUndefinierter Server!Unbekannter Fehler %s beim DekodierenUnbekanntes SSL-Protokoll: SSL deaktivieren oder alternativen Port versuchen.Unbekannte Aktion: %sUnbekannter Authentifizierungsfehler des E-Mail-ServersEntpackenArchive (rar, zip, 7z) innerhalb von Archiven entpacken.Entpacken zu tief verschachtelt [%s]%s Datei(en)/Ordner entpackt in %sEntpackenEntpacken fehlgeschlagen. %sEntpacken fehlgeschlagen. CRC-FehlerEntpacken fehlgeschlagen. Archiv benötigt ein Passwort.Entpacken fehlgeschlagen - Datei zu groß für Dateisystem (Formatierung FAT?)Entpacken fehlgeschlagen, Pfad ist zu langEntpacken fehlgeschlagen. Beachten Sie das Protokoll.Entpacken fehlgeschlagen. Konnte %s nicht finden.Entpacken fehlgeschlagen. Fehler beim Schreiben oder volle Festplatte?Fehlerhafter Login Versuch von %sUngültige NZB-Datei.RAR-Datei beschädigtUnerwünschter Dateityp in rar-Archiv %sUngewollte DateiendungenNach obenNeue Version verfügbar!HochladenNZB hochladenHochladen: .nzb .rar .zip .gz .bz2Wird hochgeladenZeit seit Startdie globalen Interface-Einstellungen verwendenÜbernehme Markierungen vom IndexerTemporäre Namen während der Nachbearbeitung verwenden. Deaktivieren, wenn das System nicht damit klar kommt.Wird verwendet, bevor eine NZB-Datei zur Warteschlange hinzugefügt wird.Verwendeter CacheNützlich, wenn ein Newsserver mehr als eine IPv4/IPv6-Adresse hatBenutzer-OrdnerBenutzer-SchlüsselBenutzer-Schlüssel (benötigt)Benutzer angemeldetBenutzer im Web-Interface angemeldetBenutzerskript kann Auftrag als fehlgeschlagen markierenBenutzernameWerteÜberprüfung und Reparatur sind nicht möglich.Überprüfung mit SFV-Datei(en) erfolgreichÜberprüfe Zertifikate bei Verbindungen zu Indexern und RSS-Quellen über HTTPS.ÜberprüfenÜberprüfe ReparaturÜberprüfung läuft …VersionSehr niedrigVideoVideobewertungSkript-Protokoll anzeigenVirus/SpamWARTE %s SekWARNUNG:ACHTUNG: "%s" wurde abgebrochen, da es ein verschlüsseltes RAR Archiv enthält (falls unterstützt, wurden alle Passwörter ausprobiert)Warnung: Aufgabe "%s" aufgrund der Bewertung (%s) abgebrochenWARNUNG: Unerwünschter Typ "%s" in RAR Datei. Unerwünschte Datei ist %s ACHTUNG: "%s" wurde angehalten, da es ein verschlüsseltes RAR Archiv enthält (falls unterstützt, wurden alle Passwörter ausprobiert)WARNUNG: Job "%s" aufgrund der Bewertung (%s) pausiert.WartenAchtungWarnung: localhost ist mehrdeutig. Verwenden Sie eine numerische IP-Adresse.WarnungenÜberwachter OrdnerGeschwindigkeit der Ordner-ÜberwachungWeb-OberflächeMittwochWöchentlich überprüfen, ob eine neue SABnzbd-Version verfügbar ist.WannJob abbrechen falls während des Downloads klar wird, dass zuviele Daten fehlenBeim Sortieren, verwende Tags aus Indexer für Titel, Saison, Episode, usw. Andernfalls wird alle Namensgebung aus dem NZB-Namen abgeleitet.Wenn das Benutzerskript einen Exit-Code ausgibt, der nicht "0" ist, wird der Auftrag als fehlgeschlagen markiert.Falls sich deine IP Adresse ändert oder SABnzbd neu startet, wird deine Session ungültigWelchen Prozentsatz deiner Downloadgeschwindigkeit SABnzbd nutzen soll, z.B. 50Welches Skript sollte für die Benachrichtigung ausgeführt werdenWer soll die E-Mail versandt haben?WikiWindows-BenachrichtigungenSchreibgeschwindigkeitXJahrJahr-Monat-OrdnerDu kannst Zugriffsrechte für Systeme ausserhalb deines Netzwerkes setzen. Benötigt die Definition einer Liste von lokalen Netzwerkbereichen.Sie müssen JavaScript aktivieren, damit Plush funktioniert!Bevor ein Bandbreitenlimit gesetzt werden kann, muss die maximale Bandbreite festgelegt werdenDeine UNRAR-Version ist %s, Wir empfehlen Version %s oder höher.
Ihre Passwort-Datei enthält mehr als 30 Passwörter, das Testen aller Passwörter dauert sehr lange. Versuchen Sie, nur nützliche Passwörter aufzulisten.Dein Pushbullet API-Key (benötigt)[%s] Fehler "%s" beim Zusammenfügen der Dateien[%s] Fehler "%s" beim Entpacken der RAR-Dateien[%s] %s Dateien zusammengefügt[%s] Keine PAR2-Sätze[%s] Ungültige PAR2-Optionen. Überprüfen Sie die Angaben in Einstellungen -> Schalter.[%s] Schnelle Überprüfung erfolgreich[%s] RAR-basierte Überprüfung ist fehlgeschlagen: %s[%s] Repariert in %s[%s] Überprüft in %s. Alle Dateien fehlerfrei.[%s] Überprüft in %s. Reparatur wird benötigt._yenc-Modul nicht gefunden!ArtikelAudioGroß- / Kleinschreibung berücksichtigenLeerentTagTageServer deaktivierenals schlecht bewertetServer aktivierenDateihStundeStundenSchlüsselwörterrestmManuellMinutenMin.Minutennicht installiertvonAusAnoderoder wenigerSeitepar2-Programmdatei nicht gefunden!passwortgeschütztSekundeSekundenBeachten Sie die ProtokolldateiSpamtextunbekanntunrar-Programmdatei nicht gefunden!unzip-Programmdatei nicht gefunden!VideoWocheSABnzbd-2.3.2/locale/en/LC_MESSAGES/SABnzbd.mo0000644000000000000000000000677113217005255016410 0ustar 00000000000000",<=R[/;67njC`{,!*G5d" U* 9G;aR= [    0 P :i :    * iE      8 9I #   6  -" P `^     
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
API Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:AdvancedConfirm History DeletionsConfirm Queue DeletionsDownloads will not unpacked.HTTPS Chain CertifcatesHow long or untill when do you want to pause? (in English!)If empty, the standard port will only listen to HTTPS.Optionally specify a filenamePause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPosts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.Replace Spaces in FoldernameReplace dots in FoldernameResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsRetry all failedScript returned exit code %s and output "%s"Seperate multiple URLs by a commaSupport the project, Donate!System Performance (Pystone)The server didn't reply properly to the helo greetingTimeleftUser script can flag job as failedWeb InterfaceWhen the user script returns a non-zero exit code, the job will be flagged as failed.disable serverenable serverunrar binary... NOT foundProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2015-07-04 10:12+0000 PO-Revision-Date: 2015-07-04 12:26+0000 Last-Translator: shypike Language-Team: Dutch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit  
SABnzbd shutdown finished.
Wait for about 5 seconds and then click the button below.

Refresh
API key incorrect, Use the API key from Config->General in your 3rd party program:API key missing, please enter the API key from Config->General into your 3rd party program:Advanced SettingsConfirm history deletionsConfirm queue deletionsDownloads will not be unpacked.HTTPS Chain CertificatesHow long or until when do you want to pause? (in English!)If empty, the SABnzbd Port set above will listen to HTTPS.Optionally specify a namePause high priority jobsPause low priority jobsPause normal priority jobsPosts will be paused until they are at least this age. Setting job priority to Force will skip the delay.Replace spaces in folder nameReplace dots in folder nameResume high priority jobsResume low priority jobsResume normal priority jobsRetry All FailedNotification script returned exit code %s and output "%s"Separate multiple URLs with a commaSupport the project, donate!System performance (Pystone)The server didn't reply properly to the hello greetingTime leftPost-processing script can flag job as failedWeb interfaceWhen the post-processing script returns a non-zero exit code, the job will be flagged as failed.Disable server:Enable server:unrar binary... NOT found!SABnzbd-2.3.2/locale/es/LC_MESSAGES/SABnzbd.mo0000644000000000000000000023304213217005255016406 0ustar 00000000000000 AoAdAB CDEF*F'GAG\GuG GGGG G H!HHHHHHH1H,I@I*SI~IAII?^JJJJJRJ[KyKKK#KKK#K$LAL HLVL.]L:L'L'LMM#M,M4M CM PM [MeM{MMM'MJM N/NONbNiN{NN)N*N N OO+O>OGOOO UO/bOhO OP*PPPP%P#PQ'Q GQQQjQqQ xQQRR"R BRcR ~RRRR!R6S-PS"~SSS"S6S(T DTOT.XT'T TTTTSTBU QU^UtUzU.U"U8UV)V1V@VPV fVpVV V VVV V#V W"W 5WAWQW*bWW6WWWW WW X3X EX OX \X hXuX|XXXXX XX XX(XY gbg!xggggghh 5hAh]hvh{hhhhhhhAh8i'Oi!wiiiiii-ij/jgIj jj&j"j9kIkOk`kok$kk k k kk kkk kl!l)l/:l jl xll'lll l llmom mm mmmmmm n#n (n2n7n;Vn-nn nn nnn6nG/owo"oooEoDp Sp^pp, q6qHq%_q#qqqq*q#r2,r%_rrr'rrrr us s ss%sssss5s 4t@tHFtnttu#u5uUuqhucuH>vov]v)Uw wwwwww wwww ww$ x2xBx0Jx{xxxxxxx x x xx xyy(y0yCyHy`ygymyyyy yy y1y"z 7z+Bznzsz{ { *{,8{e{n{{{{'{ { {/{+|E|_|;c| |||c|"=}#`}A},}*}~35~i~~~~!~!~"~&%.TZ lz 4   *+ Vaf nz ( ΀ 0 LYrM+#Dh%yR<>C"bŃ݃jh~-Єل  $;DV\pv ׅ̅  !,5DJ_n  ͆  '- 2<K^z  ˈ ׈  $:M ` m{2 Ɖ ۉ ),0VΊ  .DZkryȋߋ "!8ZqԌ  ->Na. ʍ֍ (1#E it{ 4Ў  63I3}.)&FWf m-($(@Si"&:o#)3Ԓ # / <FW o| "“Փ ޓ ' 1(6>_.͔ Ҕ ޔ//-J-x&&͕$$3>3r11ؖ & , 8 C N[k| ֗ݗ'6S X/b  Ș ژ"ԙ՚25!AW>=] + ҜWܜ4,ٝ >Xaio~28"G!jAΟҟ۟ Exݠ.@`hotv7ɡ/O-b/Ǣ #-?"m#.Σ$!FZ]o v bѤ$4 Y:d ɥ#إ"(%/LU ʦ Цݦ 0 E>/:ħ 1 ?%IoRtUǨM=k0!ک %',1?EqB+#&)JtJ&'5]x  ͬҬԬ٬߬ ', FQU ]ins{YwگRJc .-#5R$i 7 ˷ ѷ۷ 7Ib8|!E׸M  g:[ ,$!Qs:G̻,64Ck.+޼  +7Md u.]N6i¾"׾%$8] ny ʿп>l$ >B%#(-,<iq z5&>.e"3!# -1._PF2&Y&m$X& 9 E/P(  ZL[xG/@)j #$!!F h.s 7?OZ  KKSe v 9-)g*0&# J$V{* < I(#r% 76<#sA  ! 1B tA %    +8 @ NY `1j )8#? c pz!=  " :DSo !$6([8#n% G9K`v&2* '62^A,()$=b/u 5 =B !  9Pn $/3#(W-)&,'Iq.5# %.+T%*( "9\b | $-RNh+8/8)hEEU LFGQ %"H M Z hs { &> -:J4P ! $  ;6ry+1/ (3FVZ;cf,C`OcOG '7+_)O 8;D&#:% .z8 ("8AUc"% ~zWqn1u( !-0 M[k* A+ENTX"]  &5>Dd ~3C,1^>mh o }9)3] lBvQ N1Zc;2>Sq:568O+.L5U T cn ~2 * 8 GUgv)!!#(LfKo!# 1RfcB '<[(j ( ;   ?L do#* ;G gt ! ':JPVg{  (:1U #  $E)W S T^ |.$?F.  u   "       0 : L k    # # % !  = H  ^ i z  0 ; - E W l       & 7 G [ $s  3  ' "*2B#K o%|+& *28]  ?O)7y0!":P+Y5*3&Ho**+aB |6,!c>  "6Qb s ! ,0$JUI==W;;, ,:*g*CCAEA    ,>Tcj )1#ImsA %#5Y2 Sk/6C5QK i +r  _  !*!!!B!:"I"i"q""H#L#(k#(#K# $$!$'$=$S$%M% s%%7%/%& &(&-&)/& Y&d&&?&& &&-'B'JZ' '<'F'*6(a(q((A(.(%)-?)Lm)))@))*A*H*e* k*u***"*q*AD++I+++ ,),#;,6_,,,6,N, 6-B-Q-Z-c- j-v- ---H-l-Gg. . .<. //+$/ P/ ]/6h//Q/}/Fv0U061-J1x1}1111181`2Ga212 2,2)3B3Y]33333*4B4 b4m4s44444444444445 5 5555 $515 45@5I5K5S5[5z5555 55 55566 SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!
If authentication is enabled, you will need to login again.NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Also test releasesAlwaysApplication TokenApplication token (required)Apply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentCompact layoutComplete FolderComplete folder speedCompletedCompleted Download FolderConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCorrupt RAR fileCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDisable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDualView1DualView2E.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable notification scriptEnable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExecutes a custom scriptExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra history columnExtra queue columnExtracting...FILTEREDFailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send Windows notificationFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File not on serverFile setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.ForceForce DisconnectForce DownloadForcing disconnectFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGlitter has some (new) features you might like!Go to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHTTPS certificate verificationHelpHelp us translate SABnzbd in your language!
Add untranslated texts or improved existing translations here:Hibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIndexer id (%s) not found for ratings fileIndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIssuesIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job failedJob finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!Location for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLog inLog outLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMeaningMinimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateMondayMonthMoreMore thumbs down than upMovie NameMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelNZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNone of the enabled servers have the 'Default' category selected. Jobs in the queue that are not assigned to one of the server's categories will not be downloaded.NormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification ScriptNotification Sent!Notification script "%s" does not existNotificationsNotifyOSDNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly external access requires loginOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPROPAGATING %s minPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.Pre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressPropagation delayProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemember meRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRemoving jobRemoving jobsRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...Restore DefaultsResultResumeResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScriptsSearchSeason NumberSelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...SubjectSubmitSubmitted. Thank you!SundaySupport the project, Donate!Suspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETabbed layout
(separate queue and history)TaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUUencode detected, only yEnc encoding is supported [%s]Unauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UploadingUptimeUse global interface settingsUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User logged inUser logged in to the web interfaceUser script can flag job as failedUsernameValuesVerified successfully using SFV filesVerify certificates when connecting to indexers and RSS-sources using HTTPS.VerifyingVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen the user script returns a non-zero exit code, the job will be flagged as failed.When your IP address changes or SABnzbd is restarted the session will expire.Which percentage of the linespeed should SABnzbd use, e.g. 50Which script should we execute for notification?Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2017-06-22 07:07+0000 Last-Translator: Safihre Language-Team: Spanish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:31+0000 X-Generator: Launchpad (build 18511) SABnzbd no puede encontrar sus ficheros de la interfaz web en %s.
Por favor instala el programa de nuevo.

SABnzbd ha detectado información guardada de otra versión de SABnzbd
pero no puede ser reutilizada por la otra versión.

Tal vez quieras finalizar primero tu cola actual con la otra versión.

Tras ello, ejecuta este programa con la opción "--clean".
Esto eliminará la cola e historial actuales!.
SABnzbd leer el archivo "%s" SABnzbd ha detectado que el fichero sqlite3.dll no existe.

Algunos virus de de pésima calidad eliminan este fichero.
Por favor revisa la configuración de tu antivirus y quéjate a tu proveedor del AntiVirus. Tras ello reinstala SABnzbd.

SABnzbd necesita un puerto tcp/ip libre para su servidor web interno.
Se ha intentado en el puerto %s en %s, pero no está disponible.
Puede que otro software ya esté utilizando este puerto, o que SABnzbd ya esté en ejecución.

Por favor reinicia SABnzbd indicando un número de puerto diferente. SABnzbd necesita una dirección IP para su servidor web interno.
Has especificado una dirección inválida.
Valores seguros son localhost y 0.0.0.0

Por favor reinicia SABnzbd con una dirección o nombre de host correctos. SABnzbd se entrega SIN NINGUNA GARANTÍA. Este es un software libre, y eres bienvenido a redistribuirlo bajo determinadas condiciones. Está licenciado bajo la versión 2 ó posterior de GNU GENERAL PUBLIC LICENSE. %s -> Codificación desconocida%s => faltando de todos servidores, desechando%s artículos contenían duplicados inconexos%s artículos estaban mal formados.%s artículos no encontrados%s articulos removidosDirectorio %s: Error al acceder a %s%s archivos en %s%s no es un valor octal correcto%s no es una dirección de correo electrónico válida.Falta %s Resolviendo sitio 
Apago de SABnzbd exitoso.
Espere unos 5 segundos y entonces seleccione el boton abajo.

Refrescar
+Depuración+Info+Eliminar+Reparar+DescomprimirDirectorio de Backups de .nzbs0 El prioridad más alta, 100 es la prioridad más baja1x05 Episodio Directorio1x05 Temporada Directorio7ZIP conjunto "%s" es incompleta, no puede desempaquetarNo se encontró el binario de 7zaSi la autenticación esta activada, tendrás que conectarte de nuevo.NOTA: Los directorios se crean automáticamente al guardar. Puedes usar una ruta absoluta, exterior a los directorios predefinidos.Los datos no se moverán. Requiere queu SABnzbd sea reiniciado!ANTIGÜEDADAPI (sin Config)Clave APICódigo QR de la clave APIClave de API erróneo, favor ingresar la clave correcta desde Config->General en tu aplicacion externa:Falta clave de API, favor ingresar la clave desde Config->General en tu aplicacion externa:Clave API de ProwlAbortarAbortar siTrabajos abortados no pueden ser completadosAbortado, No puede ser completadoAbortado, detectamos cifradosAbortado, se ha encontrado un filtro de calificación (%s)Se interrumpió la acción porque se detectó una extensión no deseadaAceptarAcceso denegadoAcciónAcciones de descarga acordes a las reglas de filtrado.Acción cuando se detecta una extensión no deseada en archivos RARAccion cuando un archivo RAR cifrado es bajadoAcción al detectar extensiones no deseadasAccionesAñadirAñadir ficheroAñadir NZBAñadir archivos NZB Añadir planificaciónAñadir servidorNZB añadidoDirectorio de administraciónCategorías AfectadasEdadTodosTodos los archivos irán en una sola carpeta .Todas las direcciones de red locales comienzan con estos prefijos (a menudo " 192.168.1 . " )Permitir balanceo de cargaPermitir balanceo de carga con optimización para IPv6También libera de pruebaSiempreToken de aplicaciónToken de aplicación (obligatorio)Aplicar a seleccionados¿Seguro que desea reiniciar SABnzbd?¿Seguro que deseas detener SABnzbd?¿Estás seguro?ArgumentosLímite de cacheo de artículosIdentificador de artículoAl menosComo máximoAudioValoración de AudioAutenticación fallida, compruebe el usuario o la contraseña.Faltaron datos de cuenta, favor ingresar usuario/contraseña desde Config->General en tu aplicacion externa:Auto reanudarParar automáticamente cuando el espacio libre esté por debajo de este valor.
En bytes, opcionalmente seguido de K,M,G,T. Por ejemplo: "800M" ó "8G"Automáticamente ordenar elementos por antigüedad (promedio).BAtrásCopia de seguridadMala respuesta de Pushbullet (%s): %sMala respuesta de Pushover (%s): %sPlanificación incorrecta %s a las %s:%sArticulo yEnc corrupto en %sAncho de BandaBloquear actualizaciones al pasar por encimaÚltimoExaminarModelo de CPUCachear artículos en memoria para reducir el acceso a disco.
En bytes, opcionalmente seguido de K,M,G. Por ejemplo: "64M" o "128M"%s artículos cacheados (%s)CancelarNo se puede cambiar los permisos de %sError en inicio de conexion a servidor %s [%s]No se puede crear %s la carpeta %sNo se puede crear copia de seguridad del archivo %sNo se pudo crear el directorio %sImposible crear directorio final %sNo se puede crear el archivo temporal para %sNo se pudo encontrar plantillas de email en %sNo se puede encontrar la plantilla web: %s, intentando con la plantilla estandarImposible iniciar el navegador, probablemente no se le haya encontradoNo se ha podido conectar con el servicio SABHelperNo se puede leer %sDirectorio Watched %s no se puede leerNo se ha podido enviar, faltan datosNo se puede escribir en la base de datos de historia, compruebe los derechos de acceso !No se puede escribir al archivo INI %sCategoríasCategoríaNo se han guardado los cambios, y se perderán.Los cambios requieren reiniciar SABnzbd!Marcar todoChequear antes de descargarBuscar Nva VersiónVerificandoIntervalo de Chequeo (en minutos, mínimo 15). No toma efecto si utilizas el Planificador!Elije una pielLista de elementos a limpiarHa fallado la limpieza de %sLimpiarResetear contadoresHaga clic en el botón de prueba Repita a continuación para determinarHaz clic para probar los detalles introducidos.Si cierras las pestañas o el navegador, SABnzbd NO se cerrará.Lista separada por comasComentarDiseño compactoCarpeta CompletaVelocidad completa carpetaCompletadoDirectorio de descargas completadasConfig.Fichero de ConfigConfiguraciónConfirmar eliminación del historialConfirmar eliminación de la colaConfirmadoHa fallado la conexión a %s@%s, el mensaje=%s¡Conexión exitosa!¡Ha fallado la conexión!ConexionesAncho del contenedorFichero RAR corruptoNo se pudo determinar el resultado de la conexión (%s)No se pudo descomprimir %sNo se pudo escribir . Compruebe que el directorio tiene permisos de escritura .Tareas Programadas ActualesPersonalizarDDUPLICADODiariamenteDirectorios diariosLa base de datos del Historial está dañada, se ha reemplazado vaciándolaTableroOrdenar por fechaFormato de fechaDía del mesDécadaDescodificación %s falloPredeterminadoDirectorio base por defectoBorrarEliminarEliminar todoEliminar completadosEliminar FallidosEliminar tras descargar¿Eliminar todos los elementos completados del Historial?¿Elimiar todos los ficheros descargados?¿Eliminar todos los elementos de la cola?¿eliminar los elementos fallidos del historial?¡Error al eliminar %s!Detectar descargas duplicadasDetectar episodios duplicadas en serieDispositivoDispositivo al que enviar el mensajeDispositivo(s)Dispositivo(s) a los que enviar el mensajeGestión de cuotas DesactivarDeshabilitadoHTTPS deshabilitado debido a la falta de archivos CERT y KEYDescartarDesconecta del servidor de Usenet cuando la cola está vacía, o pausada.Desconectar si la cola está vacíaNotificaciones de Disco LlenoError de disco al crear el archivo %sDisco llenoDisco lleno! Pausando la colaRealiza una verificación extra basada en ficheros SFV.No se encontró autenticación válida para el feed %s¿Cada cuánto se resetea la cuota?¿No tienes proveedor de Usenet? Nosotros recomendamos probar %s.AbajoDescargarDescarga CompletadaDir de DescargaLa descarga fallóDescargar todos los archivos PAR2Descarga fallida - No está en tu(s) servidor(es)La velocidad de descarga carpetaLa descarga fallo, solo %s de los %s requeridos estan disponiblesDescargadoDescargado en %s a una media de %sB/sDescargandoDescargasVista Dual 1Vista Dual 2Por ej.P.ej. 8 ó 20ENCRIPTADOERROR:ERROR: %sERROR: Ha fallado la comprobación CRC sobre "%s"ERROR: via es muy larga (%s)ERROR: Imposible encontrar "%s"ERROR: Error de escritura (%s)Tiempo estimadoModificarEditar Detalles de NZBsino pausar siCorreoNotificación por email al terminarDestinatarioRemitente¡Email enviado!Directorio de plantillas de EmailDirección de correo electrónico a la que enviar el mensaje.Email exitosoEmergenciaVacíaFichero NZB vacío: %sEntrada RSS vacía (%s)HabilitarHabilitar 7zipHabilitar ordenar por fechaHabilitar FiltradoHabilitar GrowlHabilitar HTTPSHabilitar Ordenado de PelículasHabilitar NotifyOSDActivar notificaciones ProwlActivar notificaciones PushbulletActivar notificaciones PushoverHabilitar verificacion basada en SFVHabilitar la ordenación de Series de TVHabilitar UnzipActivar notificaciones WindowsHabilia el acceso a la interfaz con una dirección HTTPSHabilitar renombrado de directoriosHabilitar para usar menos memoria. Deshabilitar para prevenir que trabajos que se ralentizen bloqueen la cola.Activar script de notificaciónHabilitar la administración de cuotaActivar descompresión recursivaHabilitadoTerminar la ruta con un * previene que se creen directorios de trabajo.Introduzca la URLNombre del capítuloNúmero del capítuloNombre.capítuloNombre_capítuloSe ha producido un errorError "%s" al ejecutar file_join en %sError %s al ejecutar par2_repair en el conjunto %sError "%s" al ejecutar rar_unpack sobre %sError "%s" al ejecutar unzip() sobre %sError %s al ejecutar par2_repair en el conjunto %sError %s: Necesitas introducir un usuario y contraseña válidos.Error al crear la llave SSL y el certificadoError al recuperar info de la serie (%s)Error importando %sError al cargar %s, archivo corruptoError al quitar %sError al eliminar el directorio de trabajo (%s)Error al renombrar "%s" a "%s"Error al añadir %s, eliminandoError al apagarel sistemaSólo ErroresError: La longitud de ruta debería ser menor que %s.Error: Cola no esta vacía, no se puede cambiar el directorioError: Clave de sesión erróneoError: Clave de sesión requeridoErrores/AdvertenciasTodoEjemploEjecutar un script personalizadoSalir SABnzbdExtensiónAcceso a internet externaParámetros PAR2 extraColumna de historia adicionalColumna de cola extraExtrayendo...FILTRADOFallidoRegistraccion fallo para servidor %sError al crear (%s)Error al mover %s a %sNo se pudo autenticar con el servidor de correoNo se pudo cerrar el base de datos, vea el registroNo se pudo cerrar la conexión de correoCompilación de regex para término fallo: %sNo se pudo conectar al servidor de correoError al hibernar el sistemaError al importar %s ficheros desde %sError al inicializar %s@%s con la razón: %sNo se pudo inicializar la conexión TLSError al mover ficherosError al renombrar ficheros similares: %s a %sError al renombrar: %s a %sError al reiniciar NZB después de pre - chequeo (%s)Error al recuperar RSS desde %s: %sNo se pudo enviar el mensaje de ProwlFallo al mandar la notificación de WindowsNo se pudo enviar correo electrónicoNo se updo enviar el mensaje de PushbulletNo se pudo enviar el mensaje de PushoverError al suspender el sistemaError al iniciar la interfaz webError al iniciar la interfaz web: FalloFallo en tempfile.mkstempError graveError grave al guardar estadoError grave en el ensambladorCanalObtenerDescargar NZB desde URLRecuperandoRecuperando %s bloques...Recuperando bloques extra...El fichero%s está vacío, omitiendoExtensión de archivoFichero que contiene todas las contraseñas a usar en ficheros RAR protegidos.Error al unir el fichero %sNombre de archivo o ruta al Certificado SSLNombre de archivo o ruta de acceso a la cadena de HTTPS.Nombre de archivo o ruta a la clave privada SSLEl fichero no se encuentra en el servidorConjunto de ficherosNombre de archivoFiltrarFiltra la descarga de ficheros de ejemplo (e.g. un sample de vídeo).PrimeroDirectorio que contiene plantillas de email definidas por el usuario.Directorio a monitorizar en busca de ficheros .nzb.
También escanea ficheros .zip .rar y .tar.gz en busca de ficheros .nzb.Directorio/RutaDirectoriosPara correos electrónicos con autentificación, poner el nombre de usuario.Para correos electrónicos con autentificación, poner la contraseña.Para los servidores : asegúrese de que los nombres son compatibles con Windows .ForzarForzar desconexiónForzar DescargaForzar la desconexiónFormatos: .nzb, .rar, .zip, .gz, .bz2ForoLibre (Temp)Espacio libreFrecuenciaViernesDe SxxEyyAPI completaInterfaz web completaPuedes encontrar más ayuda en nuestroGBGeneralGenerar nueva clave¡Glitter tiene alguna nueva funcionalidad que puede gustarte!Ir a SABnzbdIr al AsistenteGrowlLos puertos de HTTP y de HTTPS no pueden ser igualesCertificado HTTPSCadena de Certificados HTTPSClave privada SSLPuerto HTTPSValidación del certificado HTTPSAyuda¡Ayúdanos a traducir SABnzbd en tu idioma!
Traduce textos que aun no tienen ninguna traducción o mejora los que ya lo están traducidos aquí:Hibernar PCOcultar opciones de ediciónOcultar detallesOcultar/Mostrar ficheros completadosAltaHistorialHistórico últimos 10 elementosLímite del historialMantén presionada la tecla shift para seleccionar un rangoInicioPagina principalEquipoDónde debería escuchar el Host de SABnzbd¿Durante cuánto tiempo quieres dejarlo pausado?Cantidad de descarga permitida este mes (K/M/G)INACTIVOINCOMPLETOParámetros IONiceDirección IPv6IRCInactivoSi se deja vacío, el puerto estándar escuchará por HTTPSSi obtiene este mensaje de error consecutivamente, por favor inténtelo de nuevo con otro número.
Ignorar SamplesIgnorar cualquier carpeta dentro de archivosIgnorando NZB Duplicado "%s"EnIn caso de PAUSA, necesitara escribir una contrasena para continuar el trabajo.Esta ventana desaparecerá automáticamente una vez SABnzbd se haya reiniciado.En directoriosPara poder descargar de Usenet, necesitas acceso con un proveedor. Tu proveedor de acceso a internet te lo puede dar, aunque recomendamos proveedores premium.Canal IncorrectoSe ha encontrado un fichero de cola incompatible, no se puede continuarCarpeta IncompletaFichero NZB %s incompletoSecuencia incompleta de archivos a uniriaDescripción de canal RSS incorrecta "%s"Parámetro incorrectoValor incorrecto para %s: %sContraseña incorrectamente codificado %sIdentificación del indexador (%s) no encontrado para archivo de calificacionesIndexaciónFichero NBZ inválido: %s, omitiendo (razón=%s, línea=%s)Codificación de plantilla invalido %sDirección del servidor no válida.Detalles de servidor invalidosRegistro de etapa invalido para transferencia terminada %sInvertirProblemasSe recomienda que guardes esta ubicación como favorito y la añadas a tu navegador para acceder a SABnzbd cuando quieras.Trabajo fallidoTarea finalizadaUnir ficherosUniendoMantener descargas en directorios extra.IdiomaÚltimoÚltimas advertenciasLanzar navegador al ArrancarEjecuta el navegador por defecto del sistema al arrancar SABnzbd.Limitar VelocidadEnlacesEnumerar todas las extensiones no deseadas . Por ejemplo : < b> exe < / b > o < b> exe, com < / b >Lista de extensiones de archivo que se deben eliminar después de la descarga
Por ejemplo : . nfo o nfo, sfv < /b>Lista de rangos de red localCargandoCargar de %s no se pudo completar.Falló la carga de %s con el error %sDirección IPv4 localTu buscador de internet tiene las cookies desactivadas, la configuración de la interfaz se perderá si cierras el explorador.Ubicación de la base de datos de historial y administración.
Sólo se puede cambiar si la cola está vacía.Ubicación de los ficheros de log para SABnzbd.
Requiere reiniciar SABnzbd!Ubicación donde guardar descargas finalizadas, totalmente procesaddas.
Puede ser obviado debido a categorías definidas por el usuario.Localización donde guardar descargas incompletas.
Sólo se puede cambiar si la cola est&aa; vacíUbicación donde se guardarán los ficheros .nzb.Directorio de HistorialIniciar sesiónCerrar sesiónRegistros de sucesosSe ha perdido la conexión con SABnzbd..BajaMinúsculasMBHacer compatible con WindowsEncontrado(s)Velocidad máx.Velocidad máxima de líneaMáximo número de reintentos por servidorReintentos máximosSignificadoEspacio libre mínimo para el directorio de descargas temporalesFalta clave de sesiónArtículos no encontradosModeradaLunesMesMásMás votos negativos que positivosNombre de PelículaNombre.de.peliculaNombre_de_peliculaMoviendoMoviendo...Op.MúltiplesEtiquetaClave NZBNZB añadido a la colaNombreNombre del servidor / Búsqueda de DNSNombradoNuncaNueva versión %s disponible enNueva versión disponibleSiguienteParámetros NiceAcceso denegadoNo se encontraron plantillas de correo electrónicoSin DirectoriosNo se ha podido post-procesar debido a un fallo en la verificaciónSin destinatarios no se pudo enviar el emailSin resultadosNo se ha encontrado ningún método de autenticación adecuadoNingunoNinguno de los servidores activos tiene la categoría "por defecto" seleccionada. Las tareas en espera que no estén asignadas a una categoría del servidor no serán descargadas.NormalNo encontradoNo disponible¡No hay espacio suficiente para completar las descargas!No usado¡No hay nada seleccionado!Centro de NotificaciónScript de notificación¡Notificación enviada!El script de notificación "%s" no existeNotificacionesNotifyOSDNúmero de segundos entre pasadas en busca de ficheros .nzb.Contraseña de usuario OPCIONALNombre de usuario OPCIONALApagadoSe ha encontrado una cola antigua, utilice Estado->Reparar para convertir la colaAl terminarEn caso de fallo, intentar con un NZB alternativoAl finalizar colaEn qué día del mes o semana (1=Lunes) resetea tu proveedor la cuota mensual? (Opcional con hh:mm)Sólo obtener artículos para el primer elemento de la ColaSolo acceso externo requieren conexión de usuarioSólo realiza el post-procesado en trabajos que han pasado todos los chequeos PAR2.Usar sólo para un servidor Growl remoto (servidor:puerto)Sólo utilizar este servidor para estas categorías .Abrir URL de informacionApre una ventana de Consola y teclea la línea (ejemplo)Abrir todo el folderOpcionalNZB Suplementario OpcionalContraseña opcionalNombre de usuario opcionalContraseña opcional para el servidor GrowlOpcionalmente especificar un nombre de ficheroOpciones¡ó arrastra y suelta ficheros en la propia ventana!OrdenNombre fichero originalTrabajos descolgadosOtroOtros mensajesOtro problemaFuera de retenciónPAUSADOPROPAGANDO %s minLa verificación PAR ha fallado en %s, ¡aunque el QuickCheck ha sido satisfactorio!ParametrosNumero de ParteContraseñaArchivo de contraseñasContraseña protejido por ******, favor reingresarCon contraseñaRutaPatrónPatrónPausarPausar todoPausar Descargas Durante el Post-ProcesadoPausar durantePausar 1 horaPausar 15 minutosPausar 3 horasPausar 30 minutosPausar 5 minutosPausar 6 horas¿Por cuántos minutos realizar la pausa?Pausar durante...Pausar trabajos de prioridad altaPausar trabajos de prioridad bajaPausar trabajos de prioridad normalPausar post-procesamientoEn pausaPausa las descargas al principio del post-procesado, y reanuda al terminar.Pausando NZB duplicados "%s"Porcentaje de velocidad de líneaPermisos para descargas completadasClave API personalClave privada de la API de ProwlNotas personalesTenga en cuenta que el nombre de equipo 0.0.0.0 necesitará una dirección IPv6 para el acceso externoPor favor introduce los datos de tu proveedor principal de Usenet.PuertoPuerto en que SABnzbd debería escucharError al post-procesar %s (%s)Post procesadoPost-procesar sólo trabajos verificadosPost-ProcesadoProcesamiento posterior empezadoSe ha abortado el PostProcesamiento (%s)Los mensajes serán pausados hasta que alcancen al menos esta edad. Esta espera puede evitarse si se le da el valor Forzar a la prioridad de la tarea.Script de usuario Pre-colaPreajustesPresiona la Tecla de Windows+R y teclea la línea (ejemplo)AnteriorEvitar el balanceo de cargaAnteriorPrioridadCompartiendo de cuenta probableProblema conResultado del procesadoEn procesoEl programa no ha arrancado!ProgresoDemora de la propagaciónProwlDirección IPv4 públicaPurgarPurgar NZBs completadosPurgar los NZBs fallidosPurgar NZBs fallidos y sus ficherosPurgar historialPurgar NZBsPurgar NZBs y Eliminar FicherosLimpiar Cola¿Vaciar el historial?¿Limpiar la Cola?PushbulletPushoverVersion de PythonColaEncolar los primeros 10 elementosCola terminadaLímite de elementos encolablesReparar colaChequeo Rápido...Chequeo RápidoSalirCuotaQuota disponiblePeriodo de la cuotaQuota gastado, pausando colaRRSSIntervalo de chequeo RSSEl canal RSS %s estaba vacíoSe ejecutó %sIntervaloOpciones usadas raramente. Para su significado y explicación, haga clic en el botón de Ayuda para ir al Wiki.
No cambie esto sin chequear primero en la wiki,ya que algunos ajustes tienen severas consecuencias.
Los valores por defecto se muestran entre paréntesis.Leer todas las fuentes ahoraLeer FuenteLeer entradas RSSLeer todos los canales RSSLee la ayuda en la Wiki (inglés) acerca de esto!ActualizarFrecuencia de actualizaciónFrecuencia de actualizaciónRechazarLos directorios relativos, lo son aRestanteMantenerme conectadoEliminar NZBEliminar NZB y Eliminar FicherosEliminar servidorEliminar todos los ficheros seleccionadosEliminar trabajos completadosEliminar trabajos fallidosError al eliminar %sEliminar tareaEliminar tareasRenombrarRepararHa fallado la reparación, no existen bloques de reparación suficientes (%s short)ReparandoLa reparación ha fallado, %sReparando...Repita la pruebaReemplazar espacios en el nombre de directorioReemplazar puntos en los directoriosReemplaza los puntos con espacios en los nombres de directorio.Reemplaza los espacios con guiones bajos en los nombres de directorio.DenunciarNecesitaNecesitas una cuenta ProwlNecesitas una cuenta en PushbulletNecesitas una cuenta PushoverRequiereCatReiniciarReinicializar Quota ahoraDía de reinicio del conteoReiniciarReiniciar SABnzbdReiniciar sin sesión iniciadaReiniciando SABnzbd...Restaurar valores por defectoResultadoReanudarReanudar trabajos de prioridad altaReanudar trabajos de prioridad bajaReanudar trabajos de prioridad normalReanudar post-procesamientoReanudandoPeriodo de retenciónReintentarRe-intentar todoRe-intentar todoRe-intentar todos los falladosVuelva a intentar todos los trabajos con errores¿Re-intentar todos los trabajos con errores del Historial?¿Re-intentar todos los trabajos con errores?Ejecutando scriptEjecutando script...Ejecutando script de usuario %sS01E05 Episodio DirectorioS01E05 Temporada DirectorioSABnzbd %s comenzóHost de SABnzbdContraseña de SABnzbdPuerto de SABnzbdAsistente de Configuración de SABnzbdUsuario SABnzbdVersión de SABnzbdServidor web de SABnzbdSABnzbd ha detectado un error grave:Cierre de SABnzbd terminadoSABnzbd ahora quedará ejecutando en segundo plano.Servidor SMTPComando SQL ha fallado, vea el registroSSLSábadoGuardarGuardar cambiosGuardadoGuardar de %s no se pudo completar.Guardando...Escanear directorio bajo observaciónPlanificación para servidor %s inexistentePlanificaciónScriptEl código de retorno del Script es %sScriptsBuscarNúmero de la temporadaSelecciona un idioma para la interfaz web.Selecciona sólo si tu proveedor permite conexiones SSL.SelecciónEnviarEnviar GroupEnviar notificaciones RSSEnviar de nuevo a la colaEnviar email cuando una fuente RSS añade un trabajo a la cola.Envía un email cuando el disco se ha llenado y SABnzbd se ha tenido que parar.Enviar comando group antes de solicitar los artículos.Enviar notificaciones a GrowlEnvía notificaciones al Centro de NotificaciónEnviar notificaciones a NotifyOSDEnviado(s) %s a la colaOrdenación de SeriesServidorEl servidor %s requiere usuario/contraseñaEl servidor %s utiliza un certificado HTTPS no fiableEl servidor %s se ignorará por %s minutosDetalles del servidorDirección del ServidorLa dirección del servidor «%s:%s» no es válida.Se necesita la dirección del servidorDescripción del servidorBalanceo de carga del servidorNo se puede resolver el nombre de servidorContraseña de servidorEl servidor se ha cerrado durante el loginEl servidor necesita usuario y contraseña.Error del lado servidor (código enviado por el servidor: %s); no se ha podido conseguir %s en %sServidoresAjustar patrón de permisos para ficheros/directorios completados.
En notación ocal. Por ejemplo:"755" ó "777"Indica los ajustes de tu correo electrónico saliente.¡La configuración ha terminado!¿Deberían las descargas resumirse tras reiniciarse la cuota?Mostrar TodoMostrar opciones de ediciónMostrar los FallidosVer LoggingNombre de la SerieCarpeta de la serieMostrar conexiones activasMostrar detallesMostrar interfazNombre.serieNombre_serieMostrando %s a %sde %s resultadosMostrando un resultadoApagarApagar PCApagar SABnzbdApagandoSeñal %s capturado, guardando y saliendo...TamañoHan fallado algunos ficheros al verificarse "%s"Algunos servidores ofrecen una NZB alternativa cuando falla una descarga .Lo siento, no hemos podido interpretar eso. Vuelve a intentarlo de nuevo.OrdenarOrdenar cadenaOrdenar por antigüedadOrdenar por Fecha (Más nuevo→Más viejo)Ordenar por Fecha (Más viejo→Más nuevo)Ordenar por Fecha Más nuevo→Más viejoOrdenar por Fecha Más viejo→Más nuevoOrdenar por nombre (A→Z)Ordenar por nombre (Z→A)Ordenar por nombre A→ZOrdenar por nombre Z→AOrdenar por Tamaño (Más grande→Más pequeño)Ordenar por Tamaño (Más pequeño→Más grande)Ordenar por Tamaño Más grande→Más pequeñoOrdenar por Tamaño Más pequeño→Más grandeOrdenaciónFuenteSpamEspecialVelocidadLímite de velocidadLímite de VelocidadSuspender PCIniciar AsistenteIniciando reparaciónInicio/ApagadoEstadoOpciones de estado e interfazPararDeteniendo...AsuntoEnviarEnviado. ¡Muchas gracias!Domingo¡Apoye el proyecto, haga una donación!Error sospechoso en downloaderSwitchesCarga del SistemaDirectorios del sistemaRendimiento del sistema ( Pystone )TEXTODEMASIADO GRANDEDiseño de pestañas
(separa la cola de espera y la historia)TareaCarpeta temporalDirectorio de descarga temporalEmail de pruebaNotificación de pruebaProbar ServidorTesteando información del servidorEl botón "Reparar" reiniciará SABnzbd y hará una reconstrucción
completa del contenido de la cola, preservando las descargas ya terminadas.
Esto modificará el orden de la cola.La herramienta de descarga automática para usenetLa casilla junto al nombre de la fuente debería marcarse para habilitar la fuente y que se marquen automáticamente los nuevos elementos.
Cuando una fuente se añade, sólo se cogerán los elementos nuevos y nada de lo que ya exista, salvo que presiones "Forzar Descarga".El hostname no está definido.Número de conexiones permitidas a tu proveedorEl servidor no respondió adecuadamente al saludo heloNo se han configurado conexiones. Configure al menos una conexión.Existen trabajos huérfanos en la carpeta de descarga.
Puedes escoger por eliminarlos (incluyendo los ficheros) o enviarlos de nuevo a la cola.Esta clave permitirá acceso a programas de terceros para añadir NZBs a SABnzbd.Esta clave le permitirá a programas de terceros acceso completo a SABnzbd.Este mesEste servidor no permite SSL en este puertoEsta semanaEsto evitará que se actualizen los contenidos cuando el cursor del ratón esté sobre la cola.Esto reiniciará SABnzbd.
Usalo cuando creas que el programa está colgado.
Las descargas se pausarán antes de reiniciar, y se reanudarán a continuación.Se enviará un email de prueba a tu cuentaJuevesTiempo agotadoTiempo agotado: Trate conectar en puerto diferente o encender SSL.TiempoRestanteExpiración del plazo (Timeout)TítuloPalabras clavePara: %s De: %s Fecha: %s Asunto: SABnzbd informa de un disco lleno Hola: SABnzbd ha detenido las descargas porque casi se ha llenado el disco. Haga algo de espacio y reanude SABnzbd manualmente. HoyActivar-desactivar Añadir NZBMuy poco espacio en disco forzando PAUSADemasiadas conexiones con el servidor %sDemasiadas conexiones; pause las descargas o inténtelo de nuevo más tardeSuperiorMenú superiorTotalResolver un problema¡Prueba nuestra nueva skin Glitter! Un nuevo diseño recién salido del horno, optimizado para dispositivos de sobremesa y móviles. Ves a Configuración -> General para cambiar la skin.Intenta predecir si la descarga actual se completará con éxito (ojo, esto tarda!)Tratando 7zip con la contraseña "%s"Intentando verificación por SFVTratando de buscar NZB de %sIntentando cambiar el estado de servidor inexistente %sIntentado descomprimir rar con contraseña "%s"MartesAjustesTipoURuta de acceso UNC "%s" no permitido aquiNO DESEADOError al recuperar la URL; %sEL URLGRABBER HA FALLADOUUencode detectada, la única codificación válida es Enc [%s]Acceso no autorizadoDesbloquear¡Servidor no definido!Error inespecifico mientras descodificando %sAcción desconocida: %sSe produjo un fallo de autenticación desconocido en el servidor de correoDescomprimirDescomprimir archivos (rar,zip,7z) dentro de otros archivos.El anidamiento de descompresiones ha resultado demasiado profundo [%s]Descompresos %s archivos/directorios en %sDescomprimiendoError al descomprimir, %sError de CRC al descomprimirError al descomprimir; El archivo está protegido por contraseñaAperture de archivo fallo, la via es muy largaError al descomprimir, chequea el logError al descomprimir; Imposible encontrar %sError al descomprimir; ¿Error de escritura, o tal vez el disco está lleno?Archivo NZB inusableArchivo RAR inutilizableSe ha encontrado una extensión desconocida en el fichero rar %sextensiones no deseadasEncima¡Actualización Disponible!SubirSubir NZBSubir: .nzb .rar .zip .gz, .bz2SubiendoTiempo en ActivoUsar ajustes de la interfaz globalUsa nombres temporales durante el procesado. Deshabilitalo si tu sistema se vuelve inestable con ello habilitado.Se usa precediendo a la entrada de un NZB en la cola del sistema.Caché utilizadaÚtil si un servidor de noticias tiene más de una dirección IPv4 / IPv6Directorios del usuarioClave de usuarioClave de usuario (obligatoria)Usuario conectadoUsuario conectado a la interfaz webScript de usuario puede marcar un trabajo como falladoNombre de usuarioValoresSe ha verificado correctamente utilizando ficheros SFVVerificar certificados al conectarse a indexadores y fuentes RSS usando HTTPS.VerificandoVerificando...VersiónMuy bajaVídeoPuntuaciónVer bitacora de ScriptsVirus / spamESPERAR %s segAVISO:ADVERTENCIA: Se ha abortado el trabajo "%s" debido a su puntuación (%s)ADVERTENCIA: Se ha encontrado una extensión no deseada en el fichero RAR "%s". El fichero no deseado es %s ADVERTENCIA: Se ha pausado el trabajo "%s" debido a su puntuación (%s)En esperaAdvertenciaAlerta: LOCALHOST es ambiguo, use dirección de IP numéricaAdvertenciasDirectorio a vigilarVelocidad de escaneo de la carpeta vigiladaInterfaz webMiércolesChequear semanalmente por nuevas versiones de SABnzbd.CuandoCuando este bajando, si es claro que mucha data esta faltando, aborte el trabajo.Cuando la secuencia de comandos de usuario devuelve un código de salida distinto de cero, el trabajo se marca como fallido .Cuando tu dirección IP cambie o reinicies SABnzbd, la sesión caduca.Porcentaje de la velocidad de la línea que SABnzbd debería utilizar, por ejemplo 50¿Que script deberíamos ejecutar para notificaciones?¿Quién quieres que aparezca como remitente?WikiNotificaciones Windowsvelocidad de escrituraXAñoDirectorios Año-MesDebes activar JavaScript para que pueda funcionar Plush!Debe establecer un ancho de banda máximo antes de poder establecer un límite de ancho de bandaSu versión UnRAR es %s, recomendamos la versión %s o superior.
Tu clave API personal de Pushbullet (obligatoria)[%s] Error "%s" al unir archivos[%s] Error "%s" al descomprimir ficheros RAR[%s] %s ficheros unidos.[%s] No hay conjuntos par2[%s] PAR2 ha recibido opciones incorrectas, chequea tus ajustes en Preferencias->Switches[%s] Chequeo Rápido OK[%s] Reparado en %s[%s] Verificado en %s, todos los archivos correctos[%s] Verificado en %s, se necesita repararmódulo _yenc... NO encontrado!artículosaudioajustado a mayus-minuslimpiarddíadíasdeshabilitar servidorvotados negativamentehabilitar servidorarchivohhorahoraspalabras claveRestantemmanualmínmín.minsno instaladodedesactivadoactivadooo menospáginapar2 binario... NO encontrado!protegidos por contraseñasegsegundosver fichero de logcorreo basuratextodesconocidounrar binario... NO encontradounzip binario... NO encontrado!vídeosemanaSABnzbd-2.3.2/locale/fi/LC_MESSAGES/SABnzbd.mo0000644000000000000000000024064113217005255016400 0ustar 00000000000000!$!,Bo-BdBD D FFG*G')HQHlHH HHHH II1IIIIIII1 J]C]L] _]l]|]']]5] ^'^ ;^ G^ Q^ [^e^ j^ w^^ ^^^^^^^_ _!_$'_L_ \_ i_u_#__ _____ ``$` 5` B`O`d`u````` `a4"aWaSlaaaabHb _b ibvb b bb(b.b)b&'c,Nc<{c&ccc' d5dGdcdd d d&d-d e=eYe hese{e e eeeee fff f;fNf%ef!ff+f fg!5g*Wg!gg'gg*g"'hJh#ghh!hhhhi:iBi ^ijiiiiiiiiijAjaj'xj!jjjjjk-k.% * 6/B/r--К&&%$L$q33ʛ110bjqv~ ÜԜۜ  5<Yu~ /  ' 9E_"342M5A>}= + 1W;,8e n>xȣΣݣ"!ɤA-1: @MEץ<Zr.ݦ37F~J̧-*X/_ ̨֨-"5X#r.ũש$"%7 > I jt{b$ !:, gt}#"ī%L j t  ̬0լE/L|:ǭЭ߭ %7R<UM=30q!įɯ ߯1E9B+°#)<QJc&±&'$Lgp v òȲβײܲ޲   5@D LX]bjHp˵(<@e ̻02&Ip#ļ޼( '2P46k}1ɾV;X޿7< OYyn}fv ~,'502cl0A"2 R\d x *[.&;.X ! :x?5 ,*'*$Rw)~#e8'1B%[0,<<%Y$8F$6 [ fp04 ,X9 =*'@R   ( 7A\ s+5 CIV  F;Kf} !  53&i$0##*N Tu$~/E(Z1" #>'[9A ,@)\B/ ):KQ`h o&y ( >/K{//8?Vt&("F i&C(@i*$I nMz  ,,<-i**:-("Vy6%.#/$S x)5# '; BLl *&"Q2t&/,.++Z2)0&;A[#M,#<)`#(&5/42d " " % ;E#\ Y -+%Y& / ?%e @9>?x +/7 FQ X b p{]I(r ,  *x/ & $?5X&C3 FQ` q}4D"!7 YYcS / /+&[#?96Vp 9,;[.z  8 -5:cWu )",|o#+  !* 1>AX_oB&8/D Y eox&  .3 O [%f  >;1 m6y u~ 1&( O [+g$G -/:j}"+'aS55 !*Bm%,*"- P/Z    F ^ iu~0  )/@So)()?*i Z&=+[0Y1M  & /  +  + "F i   =  V `  t  ~          ! * E 0c    !     5 @  I W #\         3!U W(x , )4F_ y%    ; YzB ! : G#Tx013 IU\w)% $*$0%U&{  '1<Fn:3Gc|!&>% $"G KV_h {%)3,`in%0 3ILE<'7"_-;:#Z~-)A)U.E y2y=  )  A  N \ q     * !!%!7! G!3S!!0!I!:" B"L"`"8w"8"7"7!#1Y#1#/#/#:$:X$8$8$ %%%%/%6%E%T%]%o%%%%% %%%%%% &&-& J&T&[&%o&& &C& &&'''<'N'`''#3(&W(~)-).)8)4*e*U$+z+8++P+$,:,"-*-I:-- ---- {..0.!.G.:/ ?/ L/V/e/D/190%k00%0<001A1 I1W1^1`1 1 11=12 2 2"=2L`2232242133-e333"313. 4#<4%`4:4!440515P5V5l5 u5"5 55-55,66I6707C7c777=77838aB8 88888 8899 +9?59bu9;9 ::B': j:v::: :.::I:dI;N;I;(G<*p<<<<<<$<6<U(=R~=3=+>*1>\>w>N>>->!?:;?.v?? ??? ??? @@ *@7@P@Y@[@a@ h@ s@~@@@@ @ @@@ @@@@@AA!A*A =AHA OAZAwAAA SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!
If authentication is enabled, you will need to login again.NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Also test releasesAlwaysApplication TokenApplication token (required)Apply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryCertificate verificationChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentCompact layoutComplete FolderComplete folder speedCompletedCompleted Download FolderConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCorrupt RAR fileCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDisable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDualView1DualView2E.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable notification scriptEnable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExecutes a custom scriptExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra history columnExtra queue columnExtracting...FILTEREDFailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send Windows notificationFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File not on serverFile setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.ForceForce DisconnectForce DownloadForcing disconnectFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGenerate new self-signed certificate and key. Requires SABnzbd restart!Glitter has some (new) features you might like!Go to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHTTPS certificate verificationHelpHelp us translate SABnzbd in your language!
Add untranslated texts or improved existing translations here:Hibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIncrease performance by forcing a lower SSL encryption strength.Indexer Categories / GroupsIndexer id (%s) not found for ratings fileIndexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to "Indexer Categories / Groups" to match more categories. Use commas to separate terms. Wildcards in the terms are supported.
More information can be found on the Wiki.IndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIssuesIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job failedJob finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!Location for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLog inLog outLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMeaningMinimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateMondayMonthMoreMore thumbs down than upMovie NameMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelNZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNone of the enabled servers have the 'Default' category selected. Jobs in the queue that are not assigned to one of the server's categories will not be downloaded.NormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification ScriptNotification Sent!Notification script "%s" does not existNotificationsNotifyOSDNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly external access requires loginOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPROPAGATING %s minPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.Pre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressPropagation delayProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge NZBs on the current pagePurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRAR files failed to verifyRAR files verified successfullyRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemember meRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRemoving jobRemoving jobsRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...Restore DefaultsResultResumeResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.SABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSSL CiphersSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScript returned exit code %s and output "%s"ScriptsSearchSeason NumberSecure (SSL) connections from SABnzbd to newsservers and HTTPS websites will be encrypted, however, validating a server's identity using its certificates is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-date local CA certificates are required.Select a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s uses an untrusted certificate [%s]Server %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...StrictSubjectSubmitSubmitted. Thank you!SundaySupport the project, Donate!Suspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETabbed layout
(separate queue and history)TaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying RAR-based verificationTrying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUUencode detected, only yEnc encoding is supported [%s]Unauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown SSL protocol: Try disabling SSL or connecting on a different port.Unknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UploadingUptimeUse global interface settingsUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User logged inUser logged in to the web interfaceUser script can flag job as failedUsernameValuesVerified successfully using SFV filesVerify certificates when connecting to indexers and RSS-sources using HTTPS.VerifyingVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen the user script returns a non-zero exit code, the job will be flagged as failed.When your IP address changes or SABnzbd is restarted the session will expire.Which percentage of the linespeed should SABnzbd use, e.g. 50Which script should we execute for notification?Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] RAR-based verification failed: %s[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2017-06-22 07:07+0000 Last-Translator: Safihre Language-Team: Finnish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:30+0000 X-Generator: Launchpad (build 18511) SABnzbd ei löydä sen web-käyttöliittymän tiedostoja polusta %s.
Ole hyvä ja asenna ohjelma uudelleen.

SABnzbd havaitsi tallennettua tietoa toisesta SABnzbd versiosta
mutta ei voi uudelleenkäyttää tietoja toisesta ohjelmasta.

Haluat ehkä ladata jonon loppuun toisella ohjelmallasi.

Tämän jälkeen, käynnistä ohjelma "--clean" muuttujalla.
Tämä tyhjentää nykyisen jonon ja historiasi!
SABnzbd luki tiedostoa "%s". SABnzbd havaitsi, että tiedosto sqlite3.dll puuttuu.

Jotkin huonosti suunnitellut viruksentorjunta ohjelmistot poistavat tämän tiedoston.
Tarkista virustorjunta ohjelmistosi, yritä asentaa SABnzbd uudelleen ja valita virustorjunta ohjelmistosi valmistajalle.

SABnzbd tarvitsee vapaan tcp/ip portin sisäiselle web-palvelimelleen.
Porttia %s kohteessa %s yritettiin käyttää , mutta se ei ollut vapaana.
Jokin toinen ohjelmisto käyttää porttia tai SABnzbd on jo käynnissä.

Ole hyvä ja uudelleenkäynnistä SABnzbd toisella porttinumerolla. SABnzbd tarvitsee vapaan tcp/ip portin sisäiselle web-palvelimelleen.
Olet määritellyt epäkelvon osoitteen.
Turvalliset arvot ovat localhost ja 0.0.0.0

Ole hyvä ja uudelleenkäynnistä SABnzbd kunnollisella isäntäosoitteella. SABnzbd ohjelmalla EI OLE MINKÄÄNLAISTA TAKUUTA. Tämä on ilmainen ohjelma ja olet vapaa levittämään sitä tiettyjen ehtojen ollessa voimassa. Se on lisensoitu GNU GENERAL PUBLIC LICENSE Versio 2 alaiseksi ja (oman valinnan mukaan) myös myöhempien versioiden. %s -> Tuntematon koodaus%s => puuttuu kaikilta palvelimilta, hylätään%s artikkelissa oli ei-vastaavia kaksoiskappaleita%s artikkelia oli väärin muotoiltuja%s artikkelia puuttui%s artikkelia poistettiin%s kansio: %s virhe käytettäessä%s tiedostoa kohteessa %s%s ei ole oikea oktaalinen arvo%s ei ole kelvollinen sähköpostiosoite%s puuttuu Selvitetään osoitetta 
SABnzbd sammutus valmis.
Odota noin 5 sekuntia ja paina sitten alapuolella olevaa nappia.

Päivitä
+ Debug+ Tiedot+Poista+Korjaa+Pura.nzb varmuuskopiokansio0 on suurin prioriteetti, 100 on pienin prioriteetti1x05 Jakso kansio1x05 Tuotantokausi kansio7ZIP setti "%s" on puutteellinen, ei voida purkaa7za ohjelmaa... EI löydy!
Jos tunnistautuminen on käytössä, sinun täytyy kirjautua sisään uudestaan.HUOM: Kansiot luodaan automaattisesti tallennuksen yhteydessä. Voit käyttää täydellisiä polkuja jos haluat tallentaa oletuskansioiden ulkopuolelle.Tiedostoja ei tulla siirtämään. Vaatii SABnzbd uudelleenkäynnistyksen!IKÄAPI (ei asetuksia)API avainAPI avaimen QR-koodiAPI avain virheellinen, käytä Asetukset->Yleiset löytyvää api avainta käyttämääsi kolmannen osapuolen ohjelmaan:API avain puuttuu, ole hyvä ja syötä Asetukset->Yleiset löytyvä api avain käyttämääsi kolmannen osapuolen ohjelmaan:Prowl API avainPeruutaPeruuta josPeruuta lataukset jotka eivät voi valmistuaPeruutettu, ei voi valmistuaPeruutettu, salattu arkisto tunnistettuPeruutettu, luokituksessa esiintyi suodatinosuma (%s)Peruutettu, ei toivottu tiedostopääte havaittuHyväksyEi käyttöoikeuttaToimintoLatauksien toiminto suodatinsääntöjen mukaan.Toiminto kun ei toivottu tiedostopääte havaitaan RAR arkistossaToiminto kun salattu RAR havaitaanToiminto kun havaitaan ei toivottu tiedostopääteToiminnotLisääLisää tiedostostaLisää NZBLisää NZB tiedostot Lisää ajastusLisää palvelinLisätty NZBHallinnollinen kansioKategoriat joita koskeeIkäKaikkiKaikki tiedostot menevät yhteen kansioon.Kaikki paikalliset verkko-osoitteet alkavat näillä etuliitteillä (yleensä "192.168.1.")Salli kuormantasausSalli kuormantasaus IPv6 optimoinnilleMyös testiversiotAinaOhjelman tokenOhjelman token (pakollinen)Käytä valittuihinOletko varma, että haluat käynnistää SABnzbd uudelleen?Oletko varma, että haluat sammuttaa SABnzbdn?Oletko varma?ParametritVälimuistirajoitus artikkeleilleArtikkelin tunnisteVähintäänEnintäänÄäniÄänen suosioVarmennus epäonnistui, tarkista käyttäjänimi/salasana.Authentikointi puuttuu, ole hyvä ja syötä käyttäjänimi/salasana Asetukset->Yleiset kolmannen osapuolen ohjelmaasi:Jatka automaattisestiKeskeytä automaattisesti kun vapaan tilan määrä on vähemmän kuin tämä arvo.
Tavuina, mutta voit laittaa perään K,M,G,T kirjaimen. Esimerkiksi: "800M" tai "8G"Järjestelee kohteet (keskimääräisen) iän mukaan.BTakaisinVarmuuskopioiVirheellinen vastaus Pushbulletilta (%s): %sVirheellinen vastaus Pushoverilta (%s): %sVirheellinen ajastus %s kohteessa %s:%sHuonosti muotoiltu yEnc artikkeli %sKaistaEstä päivitykset kun hiiri on päälläAlinSelaaProsessorin malliVälimuistita artikkelit muistissa levytapahtumien vähentämiseksi.
Tavuina, vaihtoehtoisesti lisää pääte K,M,G. Esimerkiksi: "64M" tai "128M"%s artikkelia välimuistitettu (%s)PeruutaKäyttöoikeuksien muuttaminen epäonnistui kohteelle %sPalvelimeen %s ei voida yhdistää [%s]Ei voitu luoda %s kansiota %sEi voitu luoda varmuuskopiotiedostoa kohteelle %sEi voi luoda kansiota %sEi voitu luoda lopullista kansiota %sVäliaikaistiedostoa ei voida luoda kohteelle %sSähköpostipohjia ei löydy hakemistosta %sWeb-mallia %s ei löydy, yritetään käyttää oletusmalliaSelainta ei voida käynnistää, todennäköisesti ei löydySABHelper palvelua ei voitu tavoittaaEi voida lukea %sVahdittua kansiota %s ei voida lukeaEi voida lähettää, vaaditut tiedot ovat puutteellisetHistorian tietokantaan ei voida kirjoittaa, tarkista käyttöoikeudet!Ei voitu kirjoittaa INI tiedostoa %sKategoriatKategoriaSertifikaatin varmennusMuutoksia ei ole tallennettu ja ne menetetään.Muutokset vaativat SABnzbdn uudelleenkäynnistyksen!Valitse kaikkiTarkista ennen lataamistaTarkista uusi versioTarkistetaanTarkistusväli (minuutteina, vähintään 15). Ei ole aktiivinen jos käytät Ajastinta!Valitse teema.Puhdistuslista%s puhdistaminen epäonnistui.TyhjennäNollaa laskuritPaina Toista testi -painiketta alapuolella määrittääksesiKlikkaa testataksesi syötettyjä tietoja.Selaimen tai sen välilehtien sulkeminen EI sammuta SABnzbd:tä.Pilkulla erotettu listaKommenttiTiivis käyttöliittymäValmistuneet-kansioValmistuneet-kansion nopeusValmistunutValmistuneet kansioAsetuksetAsetustiedostoAsetuksetVarmista historian poistotVarmista jonon poistotVahvistettuYhdistäminen %s@%s epäonnistui, viesti=%sYhdistäminen onnistui!Yhteys epäonnistui!YhteydetSäiliön leveysKorruptoitunut RAR arkistoYhteystestin lopputulosta ei voitu määrittää (%s)Ei voitu purkaa %sEi voitu kirjoittaa. Varmista, että sinulla on kirjoitusoikeus kansioon.Nykyiset ajastuksetMukautettuDKAKSOISKAPPALEPäivittäinPäivittäiset kansiotHistorian tietokanta on vahingoittunut, luotiin uusi tyhjä tietokantaHallintapaneeliPäivämäärän lajitteluPäivämäärän muotoKuukauden päiväVuosikymmenKohteen %s dekoodaus epäonnistuiOletusOletuskansioPoistaPoistaPoista kaikkiPoista valmistuneetPoista epäonnistuneetPoista lataamisen jälkeenPoistetaanko kaikki valmistuneet kohteet historiasta?Poistetaanko kaikki ladatut tiedostot?Poistetaanko kaikki kohteet jonosta?Poistetaanko kaikki epäonnistuneet historiasta?Kohteen %s poisto epäonnistui!Tunnista päällekkäiset latauksetTunnista identtiset jaksot sarjassaLaiteLaite johon viesti lähetetäänLaitteetLaitteet joihin viesti lähetetäänOta latausrajoituksen hallinta pois käytöstäEi käytössäHTTPS poistettu käytöstä puuttuvien CERT ja KEY tiedostojen vuoksiHylkääKatkaise yhteys Usenet palvelimeen/palvelimiin kun jono on tyhjä tai tila on keskeytetty.Katkaise yhteys kun jono on tyhjäLevy täynnä ilmoituksetLevyvirhe luotaessa tiedostoa %sLevy täynnäLevy täynnä! Pakotetaan keskeytysSuorittaa ylimääräisen varmennuksen SFV tiedostojen avulla.Ei ole käyttöoikeutta syötteeseen %sResetoidaanko rajoitus joka päivä, viikko vai kuukausi?Eikö sinulla ole usenet tarjoajaa? Suosittelemme kokeilemaan %s.AlasLataaLataus valmistuiLataukset-kansioLataus epäonnistuiLataa kaikki par2 tiedostotLataus epäonnistui - Ei ole palvelimillaLatauskansion nopeusLataaminen saattaa epäonnistua, vain %s osaa %s osasta saatavillaLadattuLadattiin ajassa %s keskilatausnopeudella %sB/sLadataanLatauksetKaksoisnäkymä1Kaksoisnäkymä2Esim.Esim. 8 tai 20SALATTUVIRHE:VIRHE: %sVIRHE: CRC epäonnistui kohteessa "%s"VIRHE: polku liian pitkä (%s)VIRHE: kohdetta "%s" ei löydyVIRHE: kirjoitusvirhe (%s)Aikaa jäljelläMuokkaaNZB tietojen muokkausMuutoin keskeytä josSähköpostiSähköposti-ilmoitus onnistuneesta latauksestaSähköpostin vastaanottajaSähköpostin lähettäjäSähköposti lähetetty!Sähköpostipohjien kansioSähköpostiosoite johon viestit lähetetään.Sähköpostitus onnistuiHälytysTyhjäTyhjä NZB tiedosto %sTyhjä RSS kohde löytyi (%s)Ota käyttöön7zip käytössäPäivämäärän lajittelu käytössäSuodatus päälleGrowl käytössäHTTPS käytössäElokuvien lajittelu käytössäNotifyOSD käytössäProwl ilmoitukset käytössäPushbullet ilmoitukset käytössäPushover ilmoitukset käytössäSFV-pohjaiset tarkistukset käytössäTV lajittelu käytössäUnzip käytössäWindows-ilmoitukset käytössäOta käyttöön käyttöliittymän käyttäminen HTTPS-osoitteesta.Kansion uudelleennimeäminen käytössäLaita päälle jos haluat ohjelman käyttävän vähemmän muistia. Ota pois päältä jos haluat estää hitaiden latauksien aiheuttavan ruuhkaa jonossa.Ilmoitusskripti päälläOta latausrajoituksen hallinta käyttöönRekursiivinen purkaminen käytössäKäytössäPolun päättäminen tähteen * estää latauskohtaisten kansioiden luomisen.Syötä osoiteJakson nimiJakson numeroJakson.nimiJakson_nimiVirheVirhe "%s" ajettaessa file_join kohteelle %sVirhe "%s" ajettaessa par2_repair setille %sVirhe "%s" ajettaessa rar_unpack kohteelle %sVirhe "%s" ajettaessa unzip() kohteelle %sVirhe %s ajettaessa par2_repair setille %sVirhe %s: Syötä kelvollinen käyttäjänimi ja salasana.Virhe luotaessa SSL avainta ja sertifikaattiaVirhe noudettaessa TV tietoja (%s)Virhe tuotaessa %sVirhe ladattaessa %s, korruptoitunut tiedosto havaittuVirhe poistettaessa %sVirhe poistettaessa työkansiota (%s)Virhe uudelleennimettäessä "%s" nimelle "%s"Virhe lisättäessä %s, poistetaanVirhe sammutettaessa järjestelmääVain virheetVirhe: Polun pituus täytyy olla alle %s.Virhe: Jono ei ole tyhjä, kansiota ei voida vaihtaa.Virhe: Istuntoavain on virheellinenVirhe: Istuntoavain vaaditaanVirheet/varoituksetKaikkiEsimerkkiSuorittaa käyttäjän skriptinPoistu SABnzbd:stäTunnisteUlkoinen ohjelman käyttöYlimääräiset PAR2 parametritYlimääräinen historiasarakeYlimääräisen jonon sarakePuretaan...SUODATETTUEpäonnistunutKirjautuminen palvelimelle %s epäonnistuiKohteen (%s) luominen epäonnistuiKohteen %s siirtäminen kohteeseen %s epäonnistuiPostipalvelimen varmennus epäonnistuiTietokannan sulkeminen epäonnistui, katso lokiSähköpostiyhteyden sulkeminen epäonnistuiRegex käännös epäonnistui hakutermille: %sPostipalvelimeen yhdistäminen epäonnistuiJärjestelmän lepotilaan laittaminen epäonnistuiVirhe tuotaessa %s tiedostoa kohteesta %sAlustaminen epäonnistui kohteessa %s@%s syy: %sTLS yhteyden aloittaminen epäonnistuiTiedostojen siirto epäonnistuiSamankaltaisen tiedoston uudelleennimeäminen epäonnistui: %s %sVirhe uudelleennimettäessä: %s %sNZB uudelleenkäynnistys epäonnistui ensimmäisen tarkistuksen jälkeen (%s)RSS noutaminen epäonnistui kohteesta %s: %sProwl viestin lähetys epäonnistuiWindows-ilmoituksen lähetys epäonnistuiSähköpostin lähetys epäonnistuiPushbullet viestin lähetys epäonnistuiPushover viestin lähetys epäonnistuiJärjestelmän valmiustilaan laittaminen epäonnistuiWeb-käyttöliittymän käynnistys epäonnistuiWeb-käyttöliittymän käynnistys epäonnistui : EpäonnistuiVirhe tiedostossa tempfile.mkstempVakava virheVakava virhe tallennettaessa tilaaVakava virhe kohteessa AssemblerSyöteNoudaNouda NZB osoitteestaNoudetaanNoudetaan %s lohkoa...Noudetaan ylimääräiset lohkot...Tiedosto %s on tyhjä, ohitetaanTiedostotunnisteTiedosto joka sisältää kaikki salasanat joita kokeillaan salattuihin RAR tiedostoihin.Tiedostoliitos %s epäonnistuiTiedostonimi tai polku HTTPS sertifikaattiin.Tiedostonimi tai polku HTTPS ketjuun.Tiedostonimi tai polku HTTPS avaimeen.Tiedostoa ei ole palvelimellaTiedostojoukkoTiedostonimiSuodataOhittaa näytetiedostot (esim. videonäytteet).EnsimmäinenKansio joka sisältää käyttäjän luomat sähköpostipohjat.Kansio jota vahditaan .nzb tiedostojen varalta.
Etsii .nzb tiedostoja myös .zip .rar ja .tar.gz arkistojen sisältä.Kansio/PolkuKansiotKirjautumisen vaativalle sähköpostille, tilin käyttäjänimi.Kirjautumisen vaativalle sähköpostille, tilin salasana.Palvelimille: varmistaa että nimet ovat Windows yhteensopivia.PakotaPakota yhteyden katkaisuPakota latausPakotetaan yhteyden katkaisuTiedostomuodot: .nzb, .rar, .zip, .gz, .bz2FoorumiVapaana (Temp)Vapaa tilaToistoPerjantaiAlkaen SxxExxTäysi APITäysi Web-käyttöliittymäLisää ohjeita löytyyGtYleisetLuo uusi avainLuo uusi itse allekirjoitettu sertifikaatti ja avain. Vaatii SABnzbd uudelleenkäynnistyksen!Glitter-teemassa on muutamia (uusia) ominaisuuksia joista saatat pitää!Siirry SABnzbd:henMene velhoonGrowlHTTP- ja HTTPS-portit eivät voi olla samojaHTTPS sertifikaattiHTTPS ketjun sertifikaatitHTTPS avainHTTPS porttiHTTPS sertfikaatin varmennusOhjeAuta meitä kääntämään SABnzbd sinun kielellesi!
Käännä tai muokkaa olemassaolevia käännöksiä täällä:HorrostilaPiilota muokkausvalinnatPiilota yksityiskohdatPiilota/näytä valmistuneet tiedostotKorkeaHistoriaVie viimeiset 10 kohdetta historiaanHistorian pituusrajoitusPaina vaihto-näppäintä pohjassa valitaksesi alueenAlkuunKotisivuIsäntäOsoite jota SABnzbdn tulisi kuunnella.Kuinka pitkään tai mihin asti haluat keskeyttää? (englanniksi!)Kuinka paljon voidaan ladata tässä kuussa (K/M/G)EI TÖITÄKESKENERÄINENIONice muuttujatIPv6 osoiteIRCToimetonJos tyhjä, oletusportti kuuntelee ainoastaan HTTPS.Jos saat tämän virhesanoman uudestaan, kokeile toista numeroa.
Ohita näytteetOhita kansiot arkistojen sisälläOhitetaan kaksoiskappale NZB "%s"KohteessaJos valitsit "Keskeytä", sinun täytyy antaa salasana ja jatkaa sen jälkeen lataamista.Mikäli SABnzbd käynnistetään uudelleen, tämä ruutu häviää automaattisesti!KansioissaJotta voit ladata usenetistä tarvitset tarjoajan. Palveluntarjoajasi saattaa tarjota sinulle sellaisen, mutta on suositeltavaa hankkia premium-tarjoaja.Puutteellinen syöteEi-tuettu jonotiedosto löytyi, ei voida jatkaaLataukset-kansioKeskeneräinen NZB tiedosto %sPuutteellinen joukko yhdistettäviä tiedostojaVirheellinen RSS syötteen kuvaus "%s"Virheellinen parametriVirheellinen arvo %s: %sVirheellisesti koodattu salasana %sLisää suorituskykyä pakottamalla alhaisempi SSL-suojaustaso.Indeksoijan kategoriat / ryhmäIndeksoijan id:tä (%s) ei löydetty arviointitiedostolleIndeksoijat voivat tarjota kategorian NZB tiedoston sisällä jonka SABnzbd yrittää vastata johonkin esimääriteltyyn kategoriaan. Voit lisäksi lisätä sanoja "Indeksoijan kategoriat / ryhmä" -kohtaan vastaamaan useampia kategorioita. Käytä pilkkuja sanojen erottamiseen. Jokerimerkit ovat tuettuna.
Lisätietoja löytyy Wikistä.IndeksoidaanVirheellinen NZB tiedosto %s, ohitetaan (syy=%s, rivi=%s)Virheellinen koodaus sähköpostipohjassa %sVirheellinen palvelimen osoite.Virheelliset palvelimen tiedotVirheellinen tila lokihistoriassa kohteelle %sKäänteinenOngelmatOn suositeltavaa, että painat linkistä hiiren oikealla ja lisäät sen kirjanmerkkeihin. Sitten voit käyttää kirjanmerkkiä kun haluat käyttää SABnzbd ohjelmaa sen ollessa käynnissä taustalla.Lataus epäonnistuiLataus valmistunutYhdistä tiedostotYhdistetäänPidä irralliset lataukset ylimääräisissä kansioissaKieliViimeinenViimeisimmät varoituksetKäynnistä selain käynnistyksen yhteydessäKäynnistää oletusselaimen kun SABnzbd käynnistetään.NopeusrajoitusLinkitLista ei toivotuista tiedostopäätteistä. Esimerkiksi: exe tai exe, comLista tiedostopäätteistä jotka poistetaan latauksen valmistuttua.
Esimerkiksi: nfo tai nfo, sfvLista paikallisista verkko-osoitealueistaLadataanKohteen %s lataaminen epäonnistuiKohteen %s lataus epäonnistui virheeseen %sPaikallinen IPv4 osoiteLocalStorage (evästeet) on pois käytöstä selaimen asetuksista. Käyttöliittymän asetukset menetetään kun selain suljetaan!Sijainti jonne tallennetaan jonon hallinnan ja historian tietokannat.
Voidaan muuttaa vain jonon ollessa tyhjä.Sijainti jonne SABnzbd ohjelman lokitiedostot tallennetaan.
Vaatii SABnzbd uudelleenkäynnistyksen!Sijainti jonne tallennetaan valmistuneet ja täysin käsitellyt ladatut kohteet.
Käyttäjän asettamat kategoriat voivat kumota tämän.Sijainti jonne tallennetaan latauksessa olevat kohteet ennen käsittelyä.
Voidaan muuttaa vain kun jono on tyhjä.Sijainti jonne .nzb tiedostot tallennetaan.LokikansioKirjaudu sisäänKirjaudu ulosLokiinkirjausMenetettiin yhteys SABnzbd:hen...MatalaPienaakkosetMtWindows yhteensopivuusVastaaEnimmäisnopeusSuurin latausnopeusEnimmäismäärä uudelleenyrityksiä yksittäiselle palvelimelle.Enimmäismäärä uudelleenyrityksilleMerkitysPienin vapaan tilan määrä väliaikaisille latauksilleIstuntoavain puuttuuPuuttuvat artikkelitKohtalainenMaanantaiKuukausiLisääEnemmän alapeukkuja kuin yläpeukkujaElokuvan nimiElokuvan.nimiElokuvan_nimiSiirretäänSiirretään...MonioperaatiotMoniosainen seliteNZB avainNZB lisätty jonoonNimiNimipalvelin / DNS-selvitysNimeäminenEi koskaanUusi versio %s saatavilla osoitteestaUusi versio saatavillaSeuraavaNice muuttujatEi pääsyäSähköpostipohjia ei löydyEi kansioitaJälkikäsittelyä ei suoritettu, koska varmennus epäonnistuiVastaanottajaa ei määritelty, sähköpostia ei lähetettyEi tuloksiaYhteensopivan varmennustavan löytäminen epäonnistuiEi mitäänAinoallakaan käytössä olevalla palvelimella ei ole 'Oletus' kategoriaa valittuna. Jonossa olevia latauksia, joita ei ole lisätty johonkin palvelimen kategoriaan ei tulla lataamaan.NormaaliEi vastaavuuttaEi saatavillaEi tarpeeksi levytilaa latauksien valmistumiseen!Ei käytössäEi mitään valittuna!IlmoituskeskusIlmoitusskriptiIlmoitus lähetetty!Ilmoitusskriptiä "%s" ei ole olemassaIlmoituksetIlmoitusOSDSkannausväli sekunteina .nzb tiedostoille.VAIHTOEHTOINEN tilin salasanaVAIHTOEHTOINEN tilin käyttäjänimiEi käytössäVanhan version jono havaittiin, käytä Tila->Korjaa muuntaaksesi jononValmistuessaEpäonnistuessa, kokeile vaihtoehtoista NZB:täKun jono on tyhjäMinä päivänä kuusta tai viikosta (1=Maanantai) palveluntarjoajasi resetoi rajoituksen? (Voit syöttää kellonajan perään hh:mm)Hae artikkelit vain jonon huipultaVain ulkoinen käyttö vaatii kirjautumisenSuorittaa jälkikäsittelyn vain niille latauksille jotka läpäisevät kaikki PAR2 tarkistukset.Käytä vain Growl etäpalvelimelle (isäntä:portti)Käytä tätä palvelinta vain näihin kategorioihin.Avaa tietoja sisältävä osoiteAvaa pääte ja kirjoita rivi (esimerkki):Avaa valmistuneet-kansioVaihtoehtoinenVaihtoehtoinen täyte-NZBVaihtoehtoinen salasana todennukseen.Vaihtoehtoinen käyttäjänimi todennukseen.Vaihtoehtoinen salasana Growl palvelimelleVaihtoehtoisesti anna tiedostonimiAsetuksetTai vedä ja pudota tiedostot tähän ikkunaan!JärjestysAlkuperäinen tiedostonimiOrvot latauksetMuuMuut viestitMuu ongelmaSäilytyksen ulkopuolellaKESKEYTETTYLEVITETÄÄN %s minPar varmennus epäonnistui kohteessa %s, mutta Pikatarkistus onnistui!ParametritOsan numeroSalasanaSalasanatiedostoSalasana on piilotettu ******, syötä uudelleenSalasanasuojattuPolkuMalliMallin avainKeskeytäKeskeytä kaikkiKeskeytä lataus jälkikäsittelyn ajaksiKeskeytä ajaksiKeskeytä tunniksiKeskeytä 15:ksi minuutiksiKeskeytä 3:ksi tunniksiKeskeytä 30:ksi minuutiksiKeskeytä 5:ksi minuutiksiKeskeytä 6:ksi tunniksiKeskeytetään kuinka moneksi minuutiksi?Keskeytä ajaksi...Keskeytä korkean prioriteetin latauksetKeskeytä alhaisen prioriteetin latauksetKeskeytä normaalin prioriteetin latauksetKeskeytä jälkikäsittelyKeskeytettyKeskeyttää lataamisen kun jälkikäsittely alkaa ja jatkaa lataamista kun se lopetetaan.Keskeytetään kaksoiskappale NZB "%s"Latausnopeuden prosenttiosuusKäyttöoikeudet valmistuneille latauksilleHenkilökohtainen API avainProwlin henkilökohtainen API avain (pakollinen)Henkilökohtaiset huomautuksetHuomioithan, että 0.0.0.0 isäntänimi vaatii IPv6 osoitteen jotta pääset ulkoverkkoonSyötä pääasiallisen usenet tarjoajasi tiedot.PorttiPortti jota SABnzbdn tulisi kuunnella.Jälkikäsittely epäonnistui kohteelle %s (%s)JälkikäsittelyJälkikäsittele vain onnistuneet latauksetJälkikäsittelyJälkikäsittely aloitettuJälkikäsittely peruutettiin (%s)Lähetykset tauotetaan kunnes ne ovat vähintään näin vanhoja. Prioriteetin asettaminen pakottamiselle ohittaa asetetun viiveen.Esijonon käyttäjän skriptiEsiasetuksetPaina Windows-nappia+R ja kirjoita seuraava rivi (esimerkki):EdellinenEstä kuormantasausEdellinenPrioriteettiMahdollinen tilin jakaminenOngelmaKäsitellyt tuloksetKäsitelläänOhjelma ei käynnistynyt!EdistyminenLevitysviiveProwlJulkinen IPv4 osoitePuhdistaPuhdista valmistuneet NZBtPuhdista epäonnistuneet NZBtPuhdista epäonnistuneet NZBt & poista tiedostotTyhjennä historiaPuhdista NZBtPuhdista NZBt & poista tiedostotPuhdista NZBt nykyiseltä sivultaTyhjennä jonoPuhdistetaanko historia?Puhdistetaanko jono?PushbulletPushoverPython versioJonoVie ensimmäiset 10 kohdetta jonoonJono valmistunutJonon pituusrajoitusJonon korjausPikatarkistus...PikatarkistetaanLopetaLatausrajoitusLatausrajoitusta jäljelläLatausrajoituksen pituusLatausrajoitus saavutettu, keskeytetään latauksetRRAR arkistoja ei voitu varmentaaRAR arkistot varmennettiin onnistuneestiRSSRSS tarkistusväliRSS syöte %s oli tyhjäAjettiin %sVäliHarvoin käytetyt asetukset. Paina Ohje-painiketta Wiki-sivustolle päästäksesi, jotta saat tietää näiden tarkoituksen ja ohjeet käyttöön.
Älä muuta ennen Wikin lukemista, koska näiden muuttamisella voi olla vakavia sivuvaikutuksia.
Oletusarvot ovat kirjoitettuna sulkeiden sisään.Lue kaikki syötteet nytLue syöteLue RSS syötteetLue kaikki RSS syötteetLue Wikin ohjeet tähän!PäivitäPäivitysväliPäivitysväliHylkääSuhteelliset kansiot jotka perustuvatJäljelläMuista minutPoista NZBPoista NZB ja tiedostotPoista palvelinPoista kaikki valitut tiedostotPoista valmistuneet latauksetPoista epäonnistuneet lataukset%s poistaminen epäonnistuiPoistetaan latausPoistetaan latauksetUudelleennimeäKorjaaKorjaaminen epäonnistui, ei tarpeeksi korjauslohkoja (%s puuttuu)KorjataanKorjaus epäonnistui, %sKorjataan...Toista testiKorvaa välilyönnit kansionimessäKorvaa pisteet kansionimessäKorvaa pisteet välilyönneillä kansionimissä.Korvaa välilyönnit alaviivoilla kansionimissä.IlmoitaVaatiiVaatii Prowl-tilinVaatii Pushbullet tilinVaatii Pushover tilinVaadittuCatNollaaResetoi latausrajoitus nytResetointipäiväKäynnistä uudelleenUudelleenkäynnistä SABnzbdKäynnistä uudelleen ilman kirjautumistaKäynnistetään SABnzbd uudelleen...Palauta oletusasetuksetTulosJatkaJatka korkean prioriteetin latauksetJatka alhaisen prioriteetin latauksetJatka normaalin prioriteetin latauksetJatka jälkikäsittelyäJatketaanSäilytysaikaYritä uudelleenYritä uudelleen kaikkiYritä uudelleen kaikkiYritä uudelleen kaikki epäonnistuneetYritä uudelleen kaikki epäonnistuneet latauksetYritetäänkö uudelleen kaikki epäonnistuneet lataukset Historiassa?Yritetäänkö uudelleen kaikki epäonnistuneet lataukset?Ajetaan skriptiAjetaan skripti...Ajetaan käyttäjän skripti %sS01E05 Jakso kansioS01E05 Tuotantokausi kansioSABnzbd %s käynnistettySABnzbd isäntäSABnzbd salasanaSABnzbd porttiSABnzbd pika-aloitus velhoSABnzbd käyttäjänimiSABnzbd versioSABnzbd web-palvelinSABnzbd havaitsi vakavan virheen:SABnzbd sammutus valmisSABnzbd käynnistettiin %s merkistökoodauksella. Tämän pitäisi olla UTF-8. Unicode-merkkejä tiedosto- ja kansionimissä sisältävät lataukset voivat aiheuttaa ongelmia.SABnzbd on nyt käynnissä taustalla.SMTP-palvelinSQL komento epäonnistui, katso lokiSSLSSL-salausLauantaiTallennaTallenna muutoksetTallennettuKohteen %s tallentaminen epäonnistuiTallennetaan...Tarkista vahdittu kansioAjastettu tuntemattomalle palvelimelle %sAjastusSkriptiSkriptin lopetuskoodi on %sSkripti palautti lopetuskoodin %s ja tulosteen "%s"SkriptitEtsiTuotantokauden numeroVarmennetut (SSL) yhteydet SABnzbdltä uutispalvelimille ja HTTPS verkkosivuille salataan, mutta palvelimen identiteetin varmennus käyttäen sen omaa sertifikaattia ei ole mahdollista. Siihen vaaditaan Python 2.7.9+, OpenSSL 1.0.2+ ja ajan tasalla olevat paikalliset CA sertifikaatit.Valitse web-käyttöliittymän kieli.Valitse vain jos tarjoajasi sallii SSL yhteydet.ValintaLähetäLähetä ryhmäLähetä RSS ilmoituksetLähetä takaisin jonoonLähetä sähköpostia kun RSS syötteestä lisätään latauksia jonoon.Lähetä sähköposti kun levy on täynnä ja SABnzbd on keskeytetty.Lähettää ryhmäkomennon ennen artikkeleiden pyytämistä.Lähetä ilmoitukset GrowliinLähetä ilmoitukset ilmoituskeskukseenLähetä ilmoitukset NotifyOSD:henLähetettiin %s jonoonSarjojen lajitteluPalvelinPalvelin %s vaatii käyttäjänimen/salasananPalvelin %s käyttää epäluotettavaa HTTPS sertifikaattiaPalvelin %s käyttää epäluotettavaa sertifikaattia [%s]Palvelin %s ohitetaan %s minuutiksiPalvelimen tiedotPalvelimen osoitePalvelimen osoite "%s:%s" ei ole kelvollinen.Palvelimen osoite vaaditaanPalvelimen kuvausPalvelimen kuormantasausPalvelimen osoitetta ei voitu selvittääPalvelimen salasanaPalvelin lopetettiin kesken kirjautumisenPalvelin vaatii käyttäjänimen ja salasanan.Palvelinpään virhe (virhekoodi %s); ei voitu noutaa %s kohteesta %sPalvelimetAseta käyttöoikeusmalli valmistuneille tiedostoille/kansioille.
Oktaalilukuna. Esimerkiksi: "755" tai "777"Sähköpostin lähtevän postin palvelimen osoite.Asennus on nyt valmis!Pitäisikö latauksia jatkaa kun latausrajoitus on resetoitu?Näytä kaikkiNäytä muokkausvalinnatNäytä epäonnistuneetNäytä lokiOhjelman nimiOhjelman nimi kansioNäytä aktiiviset yhteydetNäytä yksityiskohdatNäytä käyttöliittymäOhjelman.nimiOhjelman_nimiNäytetään %s - %s tulosta %s tuloksestaNäytetään yksi tulosSammutaSammuta tietokoneSammuta SABnzbdSammutetaanSignaali %s kaapattu, tallennetaan ja lopetetaan...KokoJotkin tiedostot eivät varmentuneet "%s" kanssaJotkin palvelimet tarjoavat vaihtoehtoisen NZB:n kun lataus epäonnistuu.Valitettavasti emme ymmärtäneet tuota. Yritä uudelleen.LajitteleLajittelumerkkijonoJärjestä iän mukaanJärjestä iän mukaan(Uusin→Vanhin)Järjestä iän mukaan(Vanhin→Uusin)Järjestä iän mukaan Uusin→VanhinJärjestä iän mukaan Vanhin→UusinJärjestä nimen mukaan (A→Z)Järjestä nimen mukaan (Z→A)Järjestä nimen mukaan A→ZJärjestä nimen mukaan Z→AJärjestä koon mukaan (Suurin→Pienin)Järjestä koon mukaan (Pienin→Suurin)Järjestä koon mukaan Suurin→PieninJärjestä koon mukaan Pienin→SuurinLajitteluLähdeSpämmiErikoisasetuksetNopeusNopeusrajoitusNopeusrajoitusLepotilaKäynnistä velhoAloitetaan korjausKäynnistys/SammutusTilaTilan ja käyttöliittymän asetuksetPysäytäPysäytetään...TiukkaOtsikkoLähetäLähetetty. Kiitos!SunnuntaiTue projektia, lahjoita!Mahdollinen virhe lataajassaMuuttujatKuormaJärjestelmäkansioJärjestelmän suorituskyky (Pystone)TEKSTILIIAN SUURIVälilehditetty käyttöliittymä
(erillinen jono ja historia)TehtäväVäliaikaiskansioVäliaikaiset lataukset kansioTestaa sähköpostiaTestaa ilmoitustaTestaa palvelintaTestataan pavelimen tietoja..."Korjaa" painike käynnistää SABnzbd uudelleen ja luo jonon
sisällön täydellisesti uudelleen, säilyttäen jo ladatut tiedostot.
Tämä muuttaa jonon järjestystä.Automaattinen usenet lataustyökaluValintaruutu syötteen nimen vieressä täytyy olla valittuna jotta syöte on päällä ja uusia kohteita tarkistetaan automaattisesti.
Kun syöte lisätään, siitä lisätään vain uusia kohteita eikä niitä jotka ovat jo julkaistu syötteessä ellet paina "Pakota lataus" -painiketta.Isäntänimeä ei ole asetettu.Tarjoajasi sallimien yhteyksien lukumäärä.Palvelin ei vastannut oikein hello-pyyntöön.Yhteyksiä ei ole asetettu. Aktivoi ainakin yksi yhteys.Latauskansiossa on orpoja latauksia.
Voit valita niiden poistamisen (sisältäen tiedostot) tai voit lähettää ne takaisin jonoon.Tämä avain antaa kolmannen osapuolen ohjelmille oikeudet lisätä NZB-tiedostoja SABnzbd-ohjelmaan.Tämä avain antaa kolmannen osapuolen ohjelmille täyden pääsyn SABnzbd-ohjelmaan.Tässä kuussaTämä palvelin ei salli SSL yhteyksiä tähän porttiinTällä viikollaTämä estää sisällön päivittämisen kun hiiren kursori on jonon päällä.Tämä uudelleenkäynnistää SABnzbdn.
Käytä sitä kun luulet ohjelman toimivan epävakaasti.
Lataaminen keskeytyy uudelleenkäynnistyksen ajaksi ja jatkuu ohjelman käynnistyttyä.Tämä lähettää testiviestin sähköpostiosoitteeseesi.TorstaiAikakatkaistiinAikakatkaistu: Yritä laittaa SSL päälle tai yhdistä toiseen porttiin.Aikaa jäljelläAikakatkaisuNimiNimen avainsanatTo: %s From: %s Date: %s Subject: SABnzbd raportoi levy täynnä Hei, SABnzbd on lopettanut lataamasta, koska levy on lähes täynnä. Ole hyvä ja tee lisää tilaa ja jatka SABnzbd käsin. TänäänPäälle/Pois Lisää NZBLevytilaa ei ole tarpeeksi, pakotetaan KESKEYTYSLiikaa yhteyksiä palvelimelle %sLiikaa yhteyksiä, keskeytä lataaminen tai yritä myöhemmin uudelleenYlinPäävalikkoYhteensäVianmääritysKokeile uutta Glitter teemaa! Uusittu design on optimoitu työpöytä- ja mobiilikäyttäjille. Mene Asetukset -> Yleiset muuttaaksesi teemaa.Yritä ennustaa latauksen valmistuminen ennen lataamista (hitaampi!)Yritetään purkaa 7zip arkistoa salasanalla "%s"Yritetään RAR-pohjaista varmennustaYritetään SFV varmennustaYritetään noutaa NZB osoitteesta %sYritettiin asettaa tila ei olemassa olevalle palvelimelle %sYritetään purkaa rar arkistoa salasanalla "%s"TiistaiHienosäätöTyyppiUTUNT polku "%s" ei ole sallittuEI TOIVOTTUOsoitteen nouto epäonnistui; %sOSOITTEENNOUTAJA KAATUIUUencode-koodaus havaittiin, vain yEnc-koodausta tuetaan [%s]Luvaton käyttöPoista estoMäärittämätön palvelin!Tuntematon virhe dekoodattaessa %sTuntematon SSL protokolla: Kokeile ottaa SSL käytöstä tai vaihda porttia.Tuntematon toiminto: %sTuntematon varmennusvirhe sähköpostipalvelimelta.PuraPurkaa arkistot (rar, zip, 7z) arkistojen sisältä.Purkaessa havaittiin liikaa pakkauskerroksia [%s]Purettiin %s tiedostoa/kansiota kohteeseen %sPuretaanPurkaminen epäonnistui, %sPurkaminen epäonnistui, CRC virhePurkaminen epäonnistui, arkisto vaatii salasananPurkaminen epäonnistui, polku on liian pitkäPurkaminen epäonnistui, katso lokiPurkaminen epäonnistui, %s ei löydyPurkaminen epäonnistui, kirjoitusvirhe tai levy täynnä?NZB tiedostoa ei voida käyttääKäyttökelvoton RAR arkistoEi toivottu tiedostopääte on rar arkistossa %sEi toivotut tiedostopäätteetYlösPäivitys saatavilla!LähetäLähetä NZBLähetä: .nzb .rar .zip .gz, .bz2LähetetäänKäynnissäoloaikaKäytä yleisiä käyttöliittymän asetuksiaKäyttää väliaikaisia nimiä kun jälkikäsittely on käynnissä. Poista käytöstä jos järjestelmäsi ei toimi oikein asetuksen ollessa päällä.Käytetään ennen NZB lisäämistä jonoon.Käytetty välimuistiHyödyllinen jos uutispalvelimella on enemmän kuin yksi IPv4/IPv6 osoiteKäyttäjähakemistotKäyttäjän avainKäyttäjän avain (pakollinen)Käyttäjä kirjautui sisäänKäyttäjä kirjautui sisään web-käyttöliittymäänKäyttäjän skripti voi merkitä latauksen epäonnistuneeksiKäyttäjänimiArvotVarmennettiin onnistuneesti SFV tiedostojen avulla.Varmenna sertifikaatit yhdistettäessä indeksoijiin ja RSS-lähteisiin HTTPS protokollan avulla.VarmennetaanVarmennetaan...VersioErittäin vähäinenVideoVideon suosioNäytä skriptien lokiVirus/roskapostiODOTA %s sekuntiaVAROITUS:VAROITUS : Peruutettiin lataus "%s", koska luokituksena on (%s)Varoitus: Latauksessa "%s" ei toivottu tiedostopääte RAR arkistossa. Ei toivottu tiedosto on %s VAROITUS : Keskeytetty lataus "%s", koska luokituksena (%s)OdotetaanVaroitusVaroitus: LOCALHOST on hämärä, käytä numeerista IP-osoitetta.VaroituksetVahdittu kansioVahditun kansion tarkistusväliWeb-käyttöliittymäKeskiviikkoTarkistaa viikottain uusimman SABnzbd version.MilloinPeruutetaan lataus, jos ladattaessa huomataan liikaa tiedostoja puuttuvanKun käyttäjän skripti palauttaa nollasta poikkeavan koodin, lataus merkitään epäonnistuneeksi.Istunto vanhenee kun IP-osoite vaihtuu tai SABnzbd käynnistetään uudelleen.Kuinka monta prosenttia latausnopeudesta SABnzbd saa käyttää, esim. 50Mikä skripti suoritetaan ilmoitukselle?Kuka näytetään viestin lähettäjänä?WikiWindows-ilmoituksetKirjoitusnopeusXVuosiVuosittaiset-Kuukausittaiset kansiotOta JavaScript käyttöön, jotta Plush toimii oikein!Sinun täytyy määrittää enimmäiskaista ennen kaistarajoituksen käyttöönottoa.UNRAR versiosi on %s, suosittelemme käyttämään versiota %s tai uudempaa.
Henkilökohtainen Pushbullet API avain (pakollinen)[%s] Virhe "%s" yhdistettäessä tiedostoja[%s] Virhe "%s" purettaessa RAR tiedostoja[%s] Liitetty %s tiedostoa[%s] Ei par2 arkistoja[%s] PAR2 vastaanotti vääränlaiset asetukset, tarkista Asetukset->Muuttujat[%s] Pikatarkistus OK[%s] RAR-pohjainen varmennus epäonnistui: %s[%s] Korjattiin ajassa %s[%s] Varmennettiin ajassa %s, kaikki tiedostot kelvollisia[%s] Varmennetiin ajassa %s, vaatii korjauksen_yenc moduulia... EI löydy!artikkeleitaäänikirjainkokoa säätävätyhjennäpvpäiväpäivääpoista palvelin käytöstäepäsuosittuota palvelin käyttööntiedostottuntituntiaavainsanatjäljellämkäsikäyttöinenminuuttimin.minuuttiaei asennettu/ei käytössäkäytössätaitai vähemmänsivupar2 ohjelmaa... EI löydy!salasanasuojattusekuntisekuntiakatso lokitiedostoroskapostitekstituntematonunrar ohjelmaa... EI löydy!unzip ohjelmaa... EI löydy!videoviikkoSABnzbd-2.3.2/locale/fr/LC_MESSAGES/SABnzbd.mo0000644000000000000000000027355313217005256016422 0ustar 00000000000000x#GoGd HrI lJyKmLWM*nM'MMMM N/N>N^N ~NNN@OHOOOWO_OgO1zOOO*OOAPYP?PQ"Q2Q:QRJQ[QQ RR#R>R[R#xR$RR RR.R: S'GS'oSSSSSS S S SSSTTT' TJHTtTU/UMUcUvU}UU UUU)U*U 'V 5V?VSVfVoVwV }VV/VhV *W6WW*AXlXnXsX%zX#XXX XY Y'Y\.Y YYZ.Z5Z UZvZ ZZZZ! [6,[-c["[[["[6\;\ W\b\Gk\l\< ]]].v]'] ]]]^ ^S!^u^ ^^^^.^"^8_G_\_d_s__ __U_` ` &`4`N` f`#p``` ```*`a6*aaasaza |aa a3a a a a aabb-b@bHb\b`b gbrb bb(bb b-cl l ll l ll(l.l)%m&Om,vm<m&mn"n'5n]nonnn n n&n-oHoeoo ooo o ooopp *p8pAp\pcp~pp%p!pp+q x/x x xx'xxy )y 3y>y]yoby yy yyzz%z;zMz `zz zzz;z>z-/{9]{{ {{ {{{6{|G||"|}}E"}Dh} }}Q~,c~~~%~#~2@R*<2%ԁFAY'p1H9; Ӄ ރ} ny *%Ą%.5H ~HnمHemqc$Hoч]A) ɈԈۈ 28 @J$]0,]qa  # 1 <G NXiz‹Njߋ# 3= V1a" + ,'': b pz/͎; /9Yci"͏#A,V*3Ő!1!S"u% " 1?PW4j  *͒   "(, U_pғ -E`vM}˔##%4ZRi<"@Ppj%#I_-g× ܗ %7=QWl ~ Ҙ  !,5<D əؙ +-Hhl Û֛  9 C OZ tŜ ؜ 2 4> S `l)0Ν(F bnt Ҟ %>Zqz !ʟ$;QFfH  '4O`p.> my  Ƣע# #*,Anv ¤ ˤ4 !+ 0;R3e3.ͥ)Bb!s  -֦,(1Zi$x!ק"-&P:wo)*T3k Ʃ өݩ  " ,"6Yl u 'Ȫ(ͪ>.5d i u//--&=&d$$3լ3 1=1o íRϭ " - 8EUfm Ǯή'D I/S   ӯ߯"Ͱα25APS>k= M+A mWwϴ,t > ͶӶ"!A'imv |EYx.ʸ!(-/NWo7a08JJj-Ⱥ/-J jt-6ӻ" -#G.k"ϼ$/ 6 A blsb$ /:: u#"Ҿ-%3LY  οֿ߿   _"0E^/X:  %CRHwUMi=0!&HM cqsxv1E4Bz+E#q)J1&El&'   ' 1?DFKQZ_ahlq v  "(-|B6 CTE*\-!'5%]lt { 'H&K:Q[ ,5hFe) 17?!w?-&/><EH.2-5= P\v -Y'"@(*i)006,g  A~T x4-bdk(s'"" $ > JrTd--"5 "?(b22g@Y*+2^:+ eBK(BD<  +"eNE.WF  :&Cj  *(/S , ;WOv  H^ n{ +  ",;S!k9,49)c*-~Z1 8 Y;p G S(2|!3 C/9s$CK b lz$9*RH '3(0 8 F P^g o{I# 'HLTpC=.l& 1 E S$a$"4 F!T5v!MoV + A N[4bD52BEM;2"E;h#8()*#Tx<L# 9Zqv ~ !")@[6c$#)59L7@,",0O=.$6I?h*('9%a'*! <&Jq-,EWZ+-6 *C"n@+B3v   4$ 5Y N S 2 9 P k %            65 l  o y a H @ Q f 7l     !      '   #>![4}6CKJ0F  " 7D H7SZ#t6OJ=[?m/'0E"cC#@/ 6,NLh; bijR+'Shx :FU]b8O3<CK&c=Z<! />RO|m 2 ! 8!E!U!d!! !!!! ! !!(!"0" 4"B"J"D"+#E#X#a###$!$ )$ 5$C$L$ U$b${$$)$$$ $% % #%/%&6%]%y%% %%%5%3&6&@I&&&Y'a's'>' ''''(.'( V( d(n(]w(#(() )b&))/))p)@U*2*a*A++4m++=++ ,,28,7k,,,1,-1 -<-B-Z-u----!---V- C.O. _.l.6.....//= /^/g/"/ /"/!/ 0)10[0.s000/001"41W1Y`1!1%1:2=2-R22l2>3?3!D3&f33+33334D4)4#5=95w5"~5 5 55555 6 (636I6O6e6k66266 6'6#7<7T7i7 777S771 8>8*W888888 88,8!9/#9$S9x9|99 99%9:;;1;=H; ;;;;1;<< !<)/<Y<*n<<<<<='= 0=G<=====.=- ><;>Ix>> >>>?0???"N? q? }???#?!? @ @(@*>@)i@*@@@@ A AA',A(TA:}A0AA A#BCB[B^qBJBC 0C>C SC"`CCCC'CCD2D D)D(E,E=E DEPE nE!zEEE-E EFF>/FnFvF FF6F G H% HH3H |HHHHHKHT)I:~I!I3I%J!5J*WJ JJJ2JHJ3 K-TKKK/KK*KL 6L'WLL/L6LILHMQM3M NR,N NNNNNNO"O8O OO ZO"eOOOOOO>O"P4)PQ^P?PPPQ?#Q?cQ=Q<Q'R'FR%nR%R<R<R:4S:oSSSSSSSgSETWTnTTTT TTTTT TUU#U&@UgUpUxU#UUUFU VV#V&6V ]VkVV(VV.|W<W!X@ YNKYMYYcZP[OR[[^[7 \ A\[O\\/Y]]]U] ]^^^/^ _*_#G_ k_U_ __` `$`\`((aQapa(a(a0a b bb b*"b Mb&Zbb<btbJc _cjc'cYcd?d WdGed:d)d ee"8e<[eae,e''f0OfIf(ff g3%gYgrgyggg&ggg/g)hzIh8hh: iGi\i#rii(i=ij%j;-j4ij\jjk2kCk KkWk^kpk kkkk@BlgllEsm m mImn+nAn Tnbn6knnenotoVp\tp9p3 q?qDqZqnqpqwqqA'rfirMrs4s7s67tnttatu(uHu7au/uuuuuvvvvv2v:vMvUvWv]v dvovwvyvvvv vvvvvvvvvvvv www w>w\wcw SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!
If authentication is enabled, you will need to login again.NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAdvancedAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")All usernames, passwords and API-keys are automatically removed from the log and the included copy of your settings.Allow load-balancingAllow load-balancing with optimization for IPv6Allow proper releasesAlso test releasesAlwaysApplication TokenApplication token (required)Apply filtersApply to SelectedAprilAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAugustAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically delete completed jobs from History. Beware that Duplicate Detection and some external tools rely on History information.Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseBypass series duplicate detection if PROPER, REAL or REPACK is detected in the download nameCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryCategory folder cannot be a subfolder of the Temporary Download Folder.Certificate hostname mismatch: the server hostname is not listed in the certificate. This is a server issue.Certificate not valid. This is most probably a server issue.Certificate verificationChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking extra filesChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentCompact layoutComplete FolderComplete folder speedCompletedCompleted Download FolderCompleted Download Folder %s is on FAT file system, limiting maximum file size to 4GBConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCorrupt RAR fileCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecemberDecoder failure: Out of memoryDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDetect identical NZB files (based on items in your History or files in .nzb Backup Folder)Detect identical episodes in series (based on "name/season/episode" of items in your History)DeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDirect UnpackDirect Unpack was automatically enabled.Disable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDo not keep any completed jobsDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDownloads will not unpacked.DualView1DualView2Duplicate NZBE.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: File too large for filesystem (%s)ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmergency expireEmergency retryEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Indexer IntegrationEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable notification scriptEnable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExecutes a custom scriptExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra history columnExtra queue columnExtracting...FILTEREDFail job (move to History)FailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send Windows notificationFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: Failing duplicate NZB "%s"FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFebruaryFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File not on serverFile setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user scripts.Folder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.For unreliable servers, will be ignored longer in case of failuresForceForce DisconnectForce DownloadForcing disconnectFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom Show SxxEyyFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGenerate new self-signed certificate and key. Requires SABnzbd restart!Glitter has some (new) features you might like!Go to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHTTPS certificate verificationHelpHelp us translate SABnzbd in your language!
Add untranslated texts or improved existing translations here:Hibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory RetentionHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How many seconds your notification will continue to be retriedHow much can be downloaded this month (K/M/G)How often (in seconds) the same notification will be sentIDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If the SABnzbd Host or Port is exposed to the internet, your current settings allow full external access to the SABnzbd interface.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIncrease performance by forcing a lower SSL encryption strength.Indexer Categories / GroupsIndexer id (%s) not found for ratings fileIndexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to "Indexer Categories / Groups" to match more categories. Use commas to separate terms. Wildcards in the terms are supported.
More information can be found on the Wiki.Indexers can supply rating information when a job is added and SABnzbd can report to the indexer if a job couldn't be completed.IndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid par2 files or invalid PAR2 parameters, cannot verify or repairInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIssuesIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.JanuaryJob "%s" is probably encrypted due to RAR with same name inside this RARJob "%s" is probably encrypted: "password" in filename "%s"Job Name as FilenameJob failedJob finishedJobsJobs will start unpacking during the downloading to reduce post-processing time. Only works for jobs that do not need repair.Join filesJoiningJulyJuneKeep all jobsKeep completed jobs maximum number of daysKeep loose downloads in extra foldersKeep maximum number of completed jobsLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!Location for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLog inLog outLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMarchMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMayMeaningMinimalMinimal: when SSL is enabled, verify the identity of the server using its certificates. Strict: verify and enforce matching hostname.Minimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateModule subprocessww missing. Expect problems with Unicoded file and directory names in downloads.MondayMonthMoreMore thumbs down than upMovie NameMovie SortingMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelMultiPar binary... NOT found!Multicore Par2NZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNone of the enabled servers have the 'Default' category selected. Jobs in the queue that are not assigned to one of the server's categories will not be downloaded.NormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification ScriptNotification Sent!Notification script "%s" does not existNotificationsNotifyOSDNovemberNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOctoberOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly external access requires loginOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOriginal Job NameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPROPAGATING %s minPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause jobs with categoryPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.Pre-queue script marked job as failedPre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressPropagation delayProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge NZBs on the current pagePurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionPython script "%s" does not have execute (+x) permission setQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRAR files failed to verifyRAR files verified successfullyRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemember meRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRemoving jobRemoving jobsRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...Restore DefaultsResultResumeResume high prioirty jobsResume jobs with categoryResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABYenc disabled: no correct version found! (Found v%s, expecting v%s)SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyencSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.SABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSSL CiphersSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScript returned exit code %s and output "%s"ScriptsScripts FolderSearchSeason NumberSecure (SSL) connections from SABnzbd to newsservers and HTTPS websites will be encrypted, however, validating a server's identity using its certificates is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-date local CA certificates are required.Secure connection to serverSecuritySelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeperate multiple URLs by a commaSeptemberSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s uses an untrusted certificate [%s]Server %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer could not complete requestServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeed up repairs by installing multicore Par2, it is available for many platforms.SpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...StrictSubjectSubmitSubmitted. Thank you!SundaySupport the project, Donate!Suspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETabbed layout
(separate queue and history)Tag jobTaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key provides identity to indexer. Check your profile on the indexer's website.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis prevents multiple repair runs by downloading all par2 files when needed.This server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying RAR-based verificationTrying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUUencode detected, only yEnc encoding is supported [%s]Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running.Unauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown SSL protocol: Try disabling SSL or connecting on a different port.Unknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, file too large for filesystem (FAT?)Unpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unsuccessful login attempt from %sUnusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UploadingUptimeUse global interface settingsUse tags from indexerUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User logged inUser logged in to the web interfaceUser script can flag job as failedUsernameValuesVerification and repair will not be possible.Verified successfully using SFV filesVerify certificates when connecting to indexers and RSS-sources using HTTPS.VerifyingVerifying repairVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen sorting, use tags from indexer for title, season, episode, etc. Otherwise all naming is derived from the NZB name.When the user script returns a non-zero exit code, the job will be flagged as failed.When your IP address changes or SABnzbd is restarted the session will expire.Which percentage of the linespeed should SABnzbd use, e.g. 50Which script should we execute for notification?Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou can set access rights for systems outside your local network. Requires List of local network ranges to be defined.You must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your password file contains more than 30 passwords, testing all these passwords takes a lot of time. Try to only list useful passwords.Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] RAR-based verification failed: %s[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2017-12-06 19:46+0000 Last-Translator: Fred <88com88@gmail.com> Language-Team: French MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:30+0000 X-Generator: Launchpad (build 18511) SABnzbd ne peut pas trouver ses fichiers d'interface web dans %s.
Veuillez réinstaller le programme.

SABnzbd a détecté des données sauvegardées avec une autre version de SABnzbd
mais ne peut réutiliser les données de l'autre programme.

Vous voudrez peut-être terminer votre première file d'attente avec l'autre programme.

Après cela, lancez ce programme avec l'option "--clean".
Cette opération effacera la file d'attente actuelle et l'historique !
SABnzbd a lu le fichier "%s". SABnzbd a détecté que le fichier sqlite3.dll est manquant.

Certains antivirus mal conçu peuvent supprimer ce fichier.
S'il vous plaît vérifier votre antivirus, essayez de ré-installer SABnzbd et plaignez vous à l'éditeur de l'antivirus.

SABnzbd a besoin d'un port tcp/ip libre pour le serveur Web interne.
La plage de ports %s à %s a été essayée mais elle n'est pas disponible.
Un autre logiciel utilise ce port ou SABnzbd est déjà en cours d'exécution.

Veuillez redémarrer SABnzbd avec un port différent. SABnzbd a besoin d'une adresse hôte valide pour son serveur Web interne.
Vous avez spécifié une adresse non valide.
Les valeurs sûres sont localhost et 0.0.0.0

Veuillez redémarrer SABnzbd avec une adresse hôte correcte. SABnzbd est fourni sans AUCUNE GARANTIE. Ce logiciel est gratuit, et vous êtes invité à le redistribuer sous certaines conditions. Il est distribué sous licence GNU GENERAL PUBLIC LICENSE Version 2 ou toute autre version ultérieure. %s -> Encodage inconnu%s => absent de tous les serveurs, rejeté%s articles avec doublons sans correspondance%s articles malformés%s articles manquants%s articles ont été retirés%s dossier : %s erreur d'accès%s fichiers dans %s%s n'est pas une valeur octale correcte%s n'est pas une adresse email valide%s manquant(s) Résolution de l'adresse 
Arrêt de SABnzbd terminé.
Veuillez attendre environ 5 secondes avant de cliquer sur le bouton ci-dessous.

Rafraîchir
+ Debug+ Info+Supprimer+Réparer+DécompresserDossier de sauvegarde des fichiers .nzb0 est la priorité la plus élevée, 100 est la priorité la plus faible1x05 Dossier Épisode1x05 Dossier SaisonLa collection 7ZIP "%s" est incomplète, impossible d'extraire les fichiersBinaire 7za ... Introuvable!
Si l'authentification est activée, vous devrez vous identifier à nouveau.NOTE: Les dossiers seront créés automatiquement lors de l'enregistrement. Il est possible d'utiliser des chemins absolus pour sauvegarder en dehors du répertoire par défaut.Les données ne seront pas déplacées. Requiert un redémarrage de SABnzbd !ÂGEAPI (aucune configuration)Clé APIClé API code QRClé API incorrecte, utilisez la clé API de la configuration générale dans votre application tierce :Clé API manquante, entrez la clé API de la configuration générale dans votre application tierce :Clé API pour ProwlAnnulerAbandonner siInterrompre les tâches qui ne peuvent être terminéesInterrompu, ne peut être achevéInterrompu, cryptage détectéTâche annulée, le filtre de classement a été vérifié (%s)Interrompu, extension indésirable détectéeAccepterAccès refuséActionActiver les téléchargements selon les règles de filtrage.Action si une extension indésirable est détecté dans les fichiers RARAction quand un RAR chiffré est téléchargéAction si une extension indésirable est détectéActionsAjouterAjouter un fichierAjouter NZBAjouter des fichiers NZB Ajouter une planificationAjouter un serveurNZB ajoutéDossier administrateurOptions avancéesCatégories affectéesÂgeTousTous les fichiers iront dans un seul dossier.Toutes les adresses de réseau local commencent par ces préfixes (souvent "192.168.1." )Tous les noms d'utilisateur, mots de passe et clés API sont automatiquement supprimés du journal et de la copie de vos réglages.Autoriser l'équilibrage de chargeAutoriser l'équilibrage de charge avec l'optimisation pour IPv6Autoriser les versions corrigées (proper)Versions de test égalementToujoursJeton (token) d'applicationJeton (token) d'application (obligatoire)Appliquer les filtresAppliquer à la sélectionAvrilÊtes-vous sûr de vouloir redémarrer SABnzbd ?Etes-vous sûr de vouloir arrêter SABnzbd ?Êtes-vous sûr ?ArgumentsLimite du cache d'articlesIdentifiant de l'articleAu moinsAu plusAudioClassement audioAoûtEchec d'authentification, vérifiez les identifiant/mot de passe.Authentification manquante, entrez vos identifiant/mot de passe de la configuration générale dans votre application tierce :Reprise autoMettre en pause lorsque l'espace libre est en-dessous de cette valeur.
En octets, peut être suivi de O,M,G,T. Par exemple : "800M" ou "8G"Supprimer automatiquement les tâches terminées de l'historique. Attention, la Détection des Doublons et certains outils externes s'appuient sur les informations de l'historique.Trier automatiquement les fichiers par âge (moyen).BRetourSecoursMauvaise réponse de Pusbullet (%s) : %sMauvaise réponse de Pushover (%s) : %sMauvaise planification %s à %s:%sArticle yEnc mal construit dans %sBande passanteBloquer rafraîchissements au survolTout en basParcourirContourner la détection des doublons si PROPER, REAL ou REPACK est détecté dans l'intitulé du téléchargementModèle de CPUMettre les articles en cache pour réduire les accès disque.
En Octets, peut être suivi de K,M,G. Par exemple : "64M" ou "128M"%s articles mis en cache (%s)AnnulerImpossible de changer les permissions pour %sImpossible de se connecter au serveur %s [%s]Impossible de créer %s dossier %sImpossible de créer le fichier de sauvegarde pour %sImpossible de créer le dossier %sImpossible de créer le dossier final %sImpossible de créer le fichier temporaire pour %sImpossible de trouver les modèles d'email dans %sImpossible de trouver le template de l'interface web : %s, nouvelle tentative avec le template standardImpossible de lancer le navigateur web, probablement pas trouvéImpossible d'accéder au service SABHelperImpossible de lire %sImpossible de lire le dossier surveillé %sImpossible d'envoyer, données requises manquantesImpossible d'écrire dans la base de données de l'historique, vérifier les droits d'accès !Impossible d'écrire dans le fichier INI %sCatégoriesCatégorieLe dossier de catégorie ne peut pas être un sous-dossier du dossier de téléchargement temporaire.Incompatibilité du nom d'hôte du certificat : le nom d'hôte du serveur n'est pas répertorié dans le certificat. Il s'agit d'un problème de serveur.Le certificat n'est pas valide. C'est probablement un problème de serveur.Vérification du certificatLes modifications n'ont pas été enregistrées et seront perdues.Les modifications nécessiteront un redémarrage de SABnzbd!Tout sélectionnerVérifiez avant de téléchargerVérifier les mises à jourVérificationVérification des fichiers supplémentairesIntervalle de vérification (en minutes, au moins 15). Inactif quand vous utilisez le Planificateur !Choisissez un thème.Nettoyer la listeÉchec du nettoyage de %s.EffacerRAZ des compteursCliquez sur le bouton de test "Répéter" ci-dessous pour déterminerCliquez pour tester les informations entrées.Fermer la fenêtre/onglet de votre navigateur NE QUITTERA PAS SABnzbd.Liste séparée par des virgulesCommentaireAffichage compactDossier completVitesse du dossier "Complete"TerminéDossier de téléchargements terminésLe système de fichiers du dossier de téléchargements terminés %s est au format FAT, limitant la taille maximale d'un fichier à 4 GoConfigurationFichier de configurationConfigurationConfirmer les suppressions de l'historiqueConfirmer les suppressions de la file d'attenteConfirméLa connexion à %s@%s a échoué, message=%sConnexion réussie!Echec de connexion !ConnectionsLargeur de l'affichageFichier RAR corrompuImpossible de déterminer le résultat de la connexion (%s)Impossible de décompresser %sImpossible d'écrire. Vérifiez que le répertoire est accessible en écriture.Planifications actuellesPersonnaliséSDOUBLONQuotidienDossiers QuotidiensBase de données d'historique endommagée, création d'une nouvelle baseTableau de bordTri par dateFormat de la dateJour du moisDécennieDécembreÉchec du décodeur : mémoire insuffisanteÉchec du décodage de %sPar défautDossier racine par défautSuppr.SupprimerTout supprimerSupprimer les terminésSupprimer les échouésSupprimer après téléchargementSupprimer tous les éléments terminés de l'historique ?Supprimer tous les fichiers téléchargés ?Supprimer tous les éléments de la file d'attente ?Supprimer tous les éléments échoués de l'historique ?Impossible de supprimer %s !Détecter les doublons de téléchargementDétecter les doublons d'épisodes de sériesDétecter les fichiers NZB identiques (en fonction des éléments de votre historique ou des fichiers .nzb du dossier de backup)Détecter les épisodes de série identiques (en fonction du modèle "nom/saison/épisode" des éléments de votre historique)AppareilAppareil sur lequel le message doit être envoyéAppareil(s)Appareil(s) auxquels doivent être envoyés les messagesDécompression DirecteLa Décompression Directe a été activée automatiquement.Désactiver la gestion de quotaDésactivéHTTPS désactivé car le certificat et la clé n'ont pas été trouvésRejeterSe déconnecter du serveur(s) Usenet lorsque la file d'attente est vide ou en pauseSe déconnecter lorsque la file d'attente est videNotifications de disque dur pleinErreur de disque lors de la création du fichier %sDisque pleinDisque plein ! Pause forcéeFait une vérification supplémentaire basée sur les fichiers SFV.Vous n'avez pas d'authentification valide pour ce flux %sNe conserver aucune tâche terminéeEst-ce que le quota se réinitialise chaque jour, semaine ou mois ?Vous n'avez pas de fournisseur usenet? Nous vous recommendons d'essayer %s.DescendreTéléchargerTéléchargement terminéDossier de téléchargementÉchec du téléchargementTélécharger tous les fichiers par2Le téléchargement a échoué - absent de vos serveur(s)Vitesse du dossier "Download"Le téléchargement pourrait échouer, seulement %s des %s requis sont disponiblesTéléchargéTéléchargé en %s à %sB/s de moyenneTéléchargementTéléchargementsLes téléchargements ne seront pas décompressés.VueDuoVVueDuoHDupliquer NZBPar ex. :Ex. : 8 ou 20CHIFFRÉERREUR:ERREUR : %sERREUR : échec CRC pour "%s"ERREUR : le fichier est trop volumineux pour le système de fichiers (%s)ERREUR : chemin trop long (%s)ERREUR : impossible de trouver "%s"ERREUR : erreur d'écriture (%s)TREÉditerÉditer les détails du NZBSinon, mettre en pause siEmailNotification par email lorsque des téléchargements sont terminésEmail du destinataireEmail de l'expéditeurEmail envoyé !Dossier des modèles d'emailAdresse email à laquelle seront envoyées les notifications.L'envoi de l'e-mail a réussiUrgenceExpiration d'urgenceNouvelle tentative d'urgenceVideFichier NZB %s videEntrée vide de flux RSS trouvée (%s)ActiverActiver 7zipActiver le tri par dateActiver le filtrageActiver GrowlActiver HTTPSActiver l'intégration de l'indexeurActiver le tri des filmsActiver NotifyOSDActiver les notifications ProwlActiver les notifications PushbulletActiver les notifications PushoverActiver les contrôles SFVActiver le tri TVActiver UnzipActiver les notifications WindowsActive l'accès à l'interface via une adresse HTTPS.Activer le renommage du dossierActiver pour moins d'utilisation de la RAM. Désactiver pour éviter que les téléchargements lents bloquent la file d'attente.Activer le script de notificationActiver la gestion de quotaActiver l'extraction récursiveActivéTerminer le chemin avec une étoile * empêche la création des dossiers de la tâche.Saisir une URLNom de l'épisodeNuméro de l'épisodeNom.ÉpisodeNom_ÉpisodeErreurErreur "%s" lors de l'exécution de file_join sur %sErreur "%s" lors de l'exécution de par2_repair sur la collection %sErreur "%s" lors de l'exécution de rar_unpack sur %sErreur "%s" lors de l'exécution de unzip() sur %sErreur %s lors de l'exécution de par2_repair sur la collection %sErreur %s: vous devez fournir un nom d'utilisateur et un mot de passe valide.Erreur lors de la création de la clé et du certificat SSLErreur lors de l'obtention des information TV (%s)Erreur lors de l'importation de %sErreur lors du chargement de %s, fichier corrompu détectéErreur lors de la suppression de %sErreur lors de la suppression du dossier de travail (%s)Erreur lors du renommage de "%s" en "%s"Erreur lors de l'ajout de %s, suppressionErreur lors de l'arrêt du systèmeErreurs uniquementErreur : la longueur du chemin doit être inférieure à %s.Erreur : La file d'attente n'est pas vide, impossible de changer le dossier.Erreur : Clé de session incorrecteErreur : Clé de session requiseErreurs/AvertissementsToutExempleExécute un script personnaliséQuitter SABnzbdExtensionAccès Internet externeParamètres PAR2 supplémentairesColonne d'historique additionnelleColonne de file d'attente supplémentaireDécompression en cours...FILTRÉFaire échouer la tâche (déplacer vers l'historique)ÉchouéÉchec de la connexion au serveur %sÉchec lors de la création de (%s)Échec lors du déplacement de %s vers %sÉchec de l'authentification au serveur de messagerieImpossible de fermer la base de données, voir le journalÉchec de la fermeture de la connexion à la messagerieEchec de la compilation de regex pour la recherche du terme : %sÉchec de connexion au serveur de messagerieÉchec de la mise en hibernatationEchec de l'importation des fichiers %s depuis %sÉchec d'initialisation de %s@%s pour la raison suivante : %sÉchec de l'initialisation de la connexion TLSImpossible de déplacer les fichiersImpossible de renommer le fichier similaire : %s en %sÉchec du renommage : %s en %sImpossible de redémarrer NZB après la pré-vérification (%s)Échec de la récupération RSS de %s : %sEchec d'envoi du message ProwlEchec d'envoi de la notification WindowsÉchec de l'envoi de l'e-mailÉchec de l'envoi du message PushbulletÉchec de l'envoi du message PushoverÉchec de la mise en veilleImpossible de démarrer l'interface webImpossible de démarrer l'interface web : Échec de duplication du NZB "%s"ÉchecÉchec dans tempfile.mkstempErreur fataleErreur fatale lors de l'enregistrementErreur fatale dans l'assembleurFévrierFlux RSSChargerImporter le NZB depuis l'URLRécupération en coursRécupération de %s blocs...Récupération des blocs supplémentaires ...Fichier %s vide, ignoréExtension du fichierLe fichier contenant tous les mots de passe sera testé sur les fichiers RAR chiffrés.La concaténation du fichiers %s a échouéNom du fichier ou chemin du certificat HTTPS.Nom du fichier ou chemin d'accès de la chaîne HTTPS.Nom du fichier ou chemin de la clé HTTPS.Fichier introuvable sur le serveurCollection de fichiersNom de fichierFiltreExclure les fichiers échantillons (par ex. les samples vidéo).PremierDossier contenant les scripts utilisateurs.Dossier contenant les modèles d'email définis par l'utilisateur.Dossier d'import automatique des fichiers .nzb.
Prends en compte également les nzb contenus dans les fichiers .zip, .rar et .tar.gz.Dossier/CheminRépertoiresIdentifiant du compte pour les envois authentifiés.Mot de passe du compte pour les envois authentifiés.Pour les serveurs : assurez-vous que les noms soient compatibles avec Windows.Pour les serveurs non fiables, sera ignorée plus longtemps en cas de défaillancesForcerForcer la déconnexionForcer le téléchargementDéconnexion forcée en coursFormats : .nzb, .rar, .zip, .gz, .bz2ForumLibre (Temp)Espace libreFréquenceVendrediÀ partir de la Série SxxEyyDepuis SxxEyyAPI complèteInterface Web complèteUne aide supplémentaire peut être trouvée sur notreGoGénéralGénérer une nouvelle cléGénérer à nouveau les certificat et clé auto-signés. Nécessite le redémarrage de SABnzbd !Glitter a des (nouvelles) fonctionnalités que vous devriez apprécier !Aller à SABnzbdAller à l'assistantGrowlLes ports HTTP et HTTPS ne peuvent pas être identiquesCertificat HTTPSCertificats de chaîne HTTPSClé HTTPSPort HTTPSVérification du certificat HTTPSAideAidez-nous à traduire SABnzbd dans votre langue !
Améliorez les traductions existantes ou ajoutez celles qui manquent ici :Mettre le PC en hibernationCacher les options d'éditionMasquer les détailsAfficher/masquer les fichiers terminésHauteHistoriqueHistorique des 10 derniers articlesConservation de l'historiqueLimite des éléments historisésMaintenez la touche Maj pour sélectionner une plageAccueilPage d'accueilHôteHôte sur lequel SABnzbd doit attendre les connexions.Combien de temps ou jusqu'à quand souhaitez-vous mettre en pause ?Tenter à nouveau votre notification pendant combien de temps (en secondes)Combien peut-être télécharger ce mois (K/M/G)À quelle fréquence la même notification sera envoyée (en secondes)A L'ARRETINCOMPLETParamètres 'IONice'Adresse IPv6IRCA l'arrêtSi vide, le port standard écoutera seulement le HTTPS.Vos paramètres actuels permettent un accès externe complet à l'interface SABnzbd si l'hôte ou le port SABnzbd est ouvert vers l'internet.Si vous obtenez ce message d'erreur à nouveau, veuillez essayer un nombre différent.
Ignorer les échantillons (Samples)Ignorer tous les dossiers à l'intérieur des archivesDoublon NZB ignoré "%s"DansEn cas de "Pause", vous devrez mettre un mot de passe pour reprendre la tâche.En cas de redémarrage de SABnzbd cet écran disparaîtra automatiquement!Dans les dossiersPour pouvoir télécharger sur les newsgroups, il est nécessaire d'avoir un fournisseur usenet. Votre FAI peut vous fournir un accès, cependant un fournisseur usenet premium est recommandé.Flux incompatibleFichier de file d'attente incompatible, impossible de continuerDossier incompletFichier NZB %s incompletSéquence incomplète des fichiers à fusionnerDescription du flux RSS incorrecte "%s"Paramètre incorrectValeur incorrecte pour %s: %sEncodage mot de passe incorrect %sAugmenter les performances en forçant un cryptage SSL plus faible.Catégories de l'indexeur / Groupesid de l'Indexer (%s) non trouvé pour le fichier des classementsLes indexeurs peuvent fournir une catégorie à l'intérieur du NZB que SABnzbd tentera de faire correspondre aux catégories définies ci-dessous. En outre, vous pouvez ajouter des termes à "Catégories de l'indexeur / Groupes" pour faire correspondre plus de catégories. Utilisez des virgules pour séparer les termes. Les caractères génériques sont pris en charge.
Plus d'informations peuvent être trouvées sur le Wiki.Les indexeurs peuvent fournir des informations de notation lorsqu'une tâche est ajoutée, et SABnzbd peut signaler à l'indexeur si une tâche n'a pas pu être terminée.IndexationFichier NZB invalide %s, ignoré (raison=%s, ligne=%s)Codage non valide pour le modèle d'email %sParamètres ou fichiers PAR2 non valides, impossible de vérifier ou réparer.Adresse du serveur erronéeParamètres serveur incorrectsÉtape de journalisation invalide dans l'historique pour %sInverserIncidentsIl est recommandé de faire un clic-droit et d'ajouter cette page à vos favoris pour accéder à SABnzbd quand il tourne en arrière plan.JanvierLa tâche "%s" est probablement chiffrée en raison d'un RAR ayant le même nom à l'intérieur de ce RARLa tâche "%s" est probablement chiffrée : "password" dans le nom de fichier "%s"Nom de la tâche en tant que nom de fichierLa tâche a échouéTâche terminéTâchesLes tâches seront décompréssées pendant le téléchargement pour réduire le temps de post-traitement. Fonctionne uniquement pour les tâches qui ne nécessitent aucune réparation.ConcaténerConcaténationJuilletJuinConserver toutes les tâchesDurée maximale d'historisation des tâches complétéesConserver les téléchargements disséminés dans des dossiers supplémentairesNombre maximum de tâches complétées historiséesLangueDernierAvertissements récentsLancer le navigateur web au démarrageLance le navigateur web par défaut au démarrage de SABnzbd.Limiter la vitesseLiensAfficher toutes les extensions indésirables. Par exemple : exe or exe, comListe des extensions de fichiers qui doivent être supprimés après le téléchargement.
nfo
ou nfo, sfvListe des plages de réseau localChargementEchec du chargement de %sLe chargement de %s a échoué avec l'erreur %sAdresse IPv4 localeLe stockage des données locales (cookies) est désactivé dans votre navigateur, les réglages de l'interface seront perdus lorsque vous fermerez votre navigateur !Emplacement de la file d'attente et de la base de données d'historique.
Ne peut être changé que lorsque la file d'attente est vide.Emplacement des fichiers journaux de SABnzbd.
Redémarrage requis !Emplacement des téléchargements terminés et post-traités.
Peut être outrepassé par les catégories définies par l'utilisateur.Emplacement de stockage des téléchargements non-traités.
Modifiable uniquement si la file d'attente est vide.Emplacement où les fichier .nzb seront archivés.Dossier du fichier journalSe connecterSe déconnecterJournalisationConnexion à SABnzbd perdue...BasseMinusculeMoRendre Windows compatibleMarsCorrespondVitesse max.Vitesse maximale de la ligneNombre maximal de tentatives par serveurNombre de tentatives maximumMaiSignificationMinimalMinimal: lorsque SSL est activé, vérifier l'identité du serveur à l'aide de ses certificats. Strict: vérifier et imposer le nom d'hôte correspondant.Espace disque minimum pour le dossier de téléchargement temporaireClé de session manquanteArticles manquantsModéréLe module subprocessww est manquant. Attendez-vous à des problèmes avec les noms de fichiers et de répertoires Unicode dans les téléchargements.LundiMoisPlusPlus de mauvais votes que de bonsNom du filmTri des filmsNom.FilmNom_FilmDéplacementDéplacement en cours...Multi-OperationsÉtiquette multi-blocFichier binaire MultiPar... NON trouvé !Par2 multi-cœurClé NZBNZB ajouté à la file d'attenteNomNameserver / DNS LookupAppellationJamaisUne nouvelle version %s est disponibleNouvelle version disponibleSuiv.Paramètres 'Nice'Aucun accèsAucun modèle email trouvésPas de dossiersPas de post-traitement car la vérification a echouéAucun destinataire déterminé, aucun email envoyéAucun résultat(s)Aucune méthode d'authentification appropriée n'a été trouvéAucunAucun des serveurs activés n'a la catégorie "Par défaut" sélectionnée. Les tâches de la file d'attente qui ne sont pas affectées à une des catégories de serveur ne seront pas téléchargées.NormaleNe correspond pasNon disponibleEspace disque insuffisant pour terminer les téléchargements!Non utiliséPas de sélection!Centre de notificationScript de notificationNotification envoyée !Le script de notification "%s" est introuvableNotificationsNotifyOSDNovembreNombre de secondes entre chaque scan du dossier pour vérifier la présence de fichiers .nzb.Mot de passe du compte (facultatif)Identifiant (facultatif)OctobreDésactivéAncienne file d'attente détectée, utiliser Statut-> Réparation pour convertir la file d'attenteUne fois terminéEn cas d'échec, essayer avec un NZB alternatifEn fin de file d'attenteA quel jour du mois ou de la semaine (1=lundi) votre fournisseur réinitialise le quota ? (Optionnel avec hh:mm)Télécharger uniquement les articles en tête de file d'attenteSeul l'accès extérieur nécessite un identifiantLimite le post-traitement aux tâches qui ont passé avec succès toutes les vérifications PAR2.Utiliser seulement pour le serveur Growl à distance (hôte:port)Utilisez uniquement ce serveur pour ces catégories.Ouvrir URL Info.Ouvrez une fenêtre de Terminal et tapez la ligne (exemple) :Ouvrir le dossier des completsOptionnelNZB supplémentaire optionnelMot de passe pour l'authentification (facultatif).Nom d'utilisateur pour l'authentification (facultatif).Mot de passe optionnel pour le serveur GrowlVous pouvez également indiquer un nom de fichierOptionsOu glissez-déposez des fichiers sur la fenêtre!OrdreNom de fichier originelNom d'origine de la tâcheTâches orphelinesAutreAutres messagesAutre problèmeEn dehors du délai de rétentionEN PAUSEPROPAGATION %s minEchec de la vérification Par sur %s, mais QuickCheck (vérification rapide) réussi !ParamètresNuméro de blocMot de passeFichier de mot de passeMot de passe masqué en ******, veuillez le ressaisir.Protégé par un mot de passeChemin d'accèsModèleModèle de cléMettre en pauseSuspendre toutMettre en pause les téléchargements lors du post-traitementPause deMettre en pause pendant 1 heureMettre en pause pendant 15 minutesMettre en pause pendant 3 heuresMettre en pause pendant 30 minutesMettre en pause pendant 5 minutesMettre en pause pendant 6 heuresMettre en pause pour combien de minutes ?Mettre en pause pour…Mettre en pause les tâches de priorité hauteMettre en pause les tâches ayant une catégorieMettre en pause les tâches de priorité faibleMettre en pause les tâches de priorité normaleMettre en pause le post-traitementEn pauseMet en pause les téléchargements au début du post-traitement et les reprend à la fin.Mise en pause du doublon NZB "%s"Pourcentage de la vitesse de la lignePermissions pour le dossier de téléchargements terminésClé API personnelleClé API personnelle pour Prowl (obligatoire)Notes personnellesS'il vous plaît soyez conscient que l'Hôte 0.0.0.0 aura besoin d'une adresse IPv6 pour les accès externesEntrez les informations de votre principal fournisseur usenet.PortPort que SABnzbd doit surveiller.Échec du post-traitement pour %s (%s)Post-traitementNe post-traiter que les tâches vérifiéesPost-traitementPost-traitement démarréPost-traitement interrompu (%s)Les publications seront mises en pause jusqu'à ce qu'elles aient au moins cet âge. La tâche commence immédiatement si elle est passée en priorité Forcée.Le script de pré-file d'attente a marqué la tâche comme échouéeScript utilisateur de pré-file d'attenteModèles prédéfinisAppuyez sur la touche Drapeau+R et tapez la ligne (exemple) :Préc.Empêcher l'équilibrage de chargePrécédentPrioritéPartage de compte probableProblème avecRésultat traitéTraitement en coursLe programme n'a pas démarré !AvancementDélai de propagationProwlAdresse IPv4 publiqueViderVider les NZB terminésPurger les NZB échouésPurger les NZBs échoués & supprimer les fichiersVider l'historiqueVider les NZBPurger les NZB & supprimer les fichiersPurger les NZBs de la page en coursVider la file d'attenteVider l'historique ?Vider la file d'attente ?PushbulletPushoverVersion de PythonLe script Python "%s" n'est pas configuré avec les permissions d’exécution (+x)File d'attenteMettre en file d'attente les 10 premiers articlesFile d'attente terminéeLimite des éléments de la file d'attenteRéparer la file d'attenteVérification rapide...Contrôle rapideQuitterQuotaQuota restantPériode du quotaQuota atteint, téléchargement mis en pauseREchec lors de la vérification des fichiers RARFichiers RAR vérifiés avec succèsRSSInvervalle de vérification RSSLe flux RSS %s était vide%s exécutéPlageOptions rarement utilisées. Pour leur sens et leur explication, cliquez sur le bouton Aide pour accéder à la page Wiki.
Ne pas les modifier sans consulter le wiki en premier, car certaines ont de graves effets secondaires.
Les valeurs par défaut sont indiquées entre parenthèses.Lire tous les flux maintenantLire le flux RSSLire les flux RSSLire tous les flux RSSConsultez le Wiki pour plus d'info à ce sujet (en anglais) !RafraîchirFréquence de rafraîchissementTaux de rafraîchissementRejeterLes chemins relatifs des dossiers sont basés surRestantSe souvenir de moiSupprimer NZBSupprimer le NZB & supprimer les fichiersSupprimer le serveurSupprimer tous les fichiers sélectionnésEffacer les tâches terminéesRetirer les tâches échouéesÉchec de la suppression de %sSuppression de la tâcheSuppression des tâchesRenommerRéparationÉchec de la réparation, pas assez de blocs de réparation (manque %s)Réparation en coursÉchec de la réparation, %sRéparation en cours...Refaire le testRemplacer les espaces dans les noms de dossierRemplacer les points dans les noms de dossierRemplace les points par des espaces dans les noms de dossierRemplace les espaces par des underscores ( _ ) dans les noms de dossiers.SignalerObligatoireNécessite un compte ProwlNécessite un compte PushbulletNécessite un compte PushoverCatObligatoireRéinitialiserRéinitialiser le quota maintenantJour de RAZRedémarrerRedémarrer SABnzbdRedémarrer sans se connecterRedémarrage de SABnzbd en cours...Rétablir les valeurs par défautRésultatReprendreReprendre les tâches de priorité hauteReprendre les tâches ayant une catégorieReprendre les tâches de priorité faibleReprendre les tâches de priorité normaleReprendre le post-traitementReprise en coursDélai de rétentionRéessayerRéessayer tousRéessayer tousRelancer toutes les tâches échouéésRéessayez toutes les tâches échouéesRéessayez toutes les tâches échouées de l'historique ?Réessayez toutes les tâches qui ont échoué ?Exécution du scriptExécution de script en cours...Exécution du script utilisateur %sS01E05 Dossier ÉpisodeS01E05 Dossier SaisonSABYenc désactivé: aucune version correcte n'a été trouvée ! (v%s trouvée, v%s attendue)Module SABYenc... NON trouvé ! v%s attendue - https://sabnzbd.org/sabyencSABnzbd %s démarréHôte SABnzbdMot de passe SABnzbdPort SABnzbdAssistant de configuration SABnzbdIdentifiant SABnzbdVersion de SABnzbdServeur web SABnzbdSABnzbd a détecté une erreur fatale :Arrêt de SABnzbd terminéSABnzbd a été démarré avec l'encodage %s, celui-ci devrait être UTF-8. Attendez-vous à des problèmes avec les noms de fichiers et de répertoires Unicode dans les téléchargements.SABnzbd fonctionnera dorénavant en arrière plan.Serveur SMTPEchec de la commande SQL, voir le journalSSLChiffrements SSLSamediEnregistrerEnregistrer les modificationsEnregistréL'enregistrement de %s a échouéEnregistrement..Analyser le dossier surveilléPlanification pour un serveur non existant %sPlanificationScriptLe code script de sortie est %sLe script a renvoyé le code de sortie %s et le résultat "%s"ScriptsDossier des scriptsRechercherNuméro de la saisonLes connexions sécurisées (SSL) de SABnzbd vers les serveurs Usenet et aux sites HTTPS seront chiffrées, mais la validation de l'identité d'un serveur à l'aide de ses certificats n'est pas possible. Python 2.7.9 ou supérieur, OpenSSL 1.0.2 ou supérieur, et des certificats locaux AC à jour sont requis.Connexion sécurisée au serveurSécuritéChoisir la langue de l'interface web.Cochez uniquement si votre fournisseur usenet permet les connexions SSL.SélectionEnvoyerEnvoyer 'Group'Envoyer les notifications RSSRenvoyer dans la file d'attenteEnvoie un email quand un flux RSS ajoute un fichier dans la file d'attente.Envoie un email lorsque le disque dur est plein et que SABnzbd a été mis en pause.Envoyer la commande 'group' avant la demande des articles.Envoie les notifications à GrowlEnvoyer des notifications au centre de notificationEnvoie les notifications à NotifyOSD%s envoyé dans la file d'attenteSéparez les URL multiples par une virguleSeptembreTri des sériesServeurLe serveur %s requiert un identifiant/mot de passeLe serveur %s utilise un certificat de sécurité HTTPS non authentifiéLe serveur %s utilise un certificat peu fiable [%s]Le serveur %s sera ignoré pendant %s minutesDétails du serveurAdresse du serveurL' adresse du serveur "%s:%s" n'est pas valide.Adresse du serveur requiseLe serveur n'a pas pu terminer la requêteDescription du serveurEquilibrage de charge du serveurResolution du nom de serveur impossibleMot de passe du serveurLe serveur a interrompu l'ouverture de session.Le serveur requiert un identifiant et un mot de passe.Erreur du côté serveur (code serveur %s) ; n'a pas pu obtenir %s sur %sServeursAppliquer ce modèle de permissions aux fichiers/dossiers téléchargés.
En notation octale. Par exemple : "755" ou "777"Entrez le serveur de courrier sortant de votre FAI.La configuration est terminée!Le téléchargement devrait-il reprendre après que le quota soit réinitialisé ?Afficher ToutAfficher les options d'éditionAfficher les échouésAfficher le journalNom de la sérieDossier du nom de sérieAfficher les connexions activesAfficher les détailsAfficher l’interfaceNom.SérieNom_SérieAffiche %s de %s sur %s résultatsAffichage d'un seul résultatArrêterÉteindre le PCArrêter SABnzbdArrêt en cours...Signal %s intercepté, enregistrement et fermeture en cours...TailleCertains fichiers n'ont pas pu être vérifiés "%s"Certains serveurs proposent un NZB alternatif lorsqu'un téléchargement échoue.Désolé, nous n'avons pas pu interpréter ça. Essayez encore.TrierChaîne de caractères de triTrier par âgeTrier par âge (Plus récent→Moins récent)Trier par âge (Moins récent→Plus récent)Trier par âge Plus récent→Moins récentTrier par Age Moins récent→Plus récentTrier par nom (A→Z)Trier par nom (Z→A)Trier par nom A→ZTrier par nom Z→ATrier par taille (Plus grand→Plus petit)Trier par taille (Plus petit→Plus grand)Trier par taille Plus grand→Plus petitTrier par taille Plus petit→Plus grandTriageSourceSpamSpécialVitesseVitesse limiteAccélérez les réparations en installant Par2 multi-coeur, disponible sous de nombreuses plateformes.Limite de vitesseMettre le PC en veilleLancer l'assistantRéparation en coursDémarrage/ArrêtStatutOptions de statut et d'interfaceArrêterArrêt en cours...StrictSujetSoumettreSoumis. Merci !DimancheSoutenez le projet, faites un don !Erreur suspecte dans le téléchargeurSwitchesSysloadDossiers systèmePerformance du système ( Pystone )TEXTETROP VOLUMINEUXMise en page par onglets
(file d'attente et historique séparés)Taguer la tâcheTâcheDossier temporaireDossier temporaire de téléchargementEmail de testTest de NotificationTester le serveurTest des détails du serveur en cours...Ceci redémarre SABnzbd et fait une complète reconstruction
de la file d'attente, tout en conservant les fichiers déjà téléchargés.
Ceci modifiera l'ordre de la file d'attente.L'outil de téléchargement usenet automatiqueLa case à cocher à coté du nom du flux doit être cochée pour que le flux soit activé et qu'il soit pris en compte dans la vérification des nouveaux téléchargements.
Quant un flux est ajouté, seuls les nouveaux téléchargements seront pris en compte à moins de cliquer sur "Forcer téléchargements".Le nom d'hôte n'est pas défini.Le nombre de connexions autorisées par votre fournisseur usenetLe serveur n'a pas répondu correctement au protocole d'identification "hello"Aucune connexion n'est configurée. Veuillez définir au moins une connexion.Il y a des dossiers orphelins dans le répertoire de téléchargement.
Vous pouvez choisir de les supprimer (y compris les fichiers) ou de les renvoyer dans la file d'attente.Cette clé fournit l'identité à l'indexeur. Vérifiez votre profil sur le site web de l'indexeur.Cette clé permettra aux programmes tiers de pouvoir ajouter des NZB à SABnzbd.Cette clé permettra aux programmes tiers d'avoir un accès complet à SABnzbd.Ce moisCeci évite les réparations multiples en téléchargeant tous les fichiers par2 nécessaires.Ce serveur n'authorise pas de connexion SSL sur ce portCette semainePermet d'éviter le rafraîchisssment du contenu quand la souris survole la file d'attente.Ceci redémarrera SABnzbd.
Utilisez cette fonction si vous pensez avoir un problème de stabilité.
Les téléchargements en cours seront mis en pause puis repris.Ceci enverra un email de test sur votre compte.JeudiDélai dépasséDélai dépassé : essayez d'activer SSL ou de vous connecter sur un port différent.Temps restantDélai d'expirationTitreMots-clés titreA : %s De : %s Date : %s Sujet : Alerte SABnzbd : disque plein Salut, SABnzbd a arrêté le téléchargement car le disque est presque plein. Merci de faire de la place avant de reprendre manuellement le téléchargement sous SABnzbd. Aujourd'huiAfficher / Masquer Ajout NZBEspace disque faible, PAUSE forcéeTrop de connexions au serveur %sTrop de connexions, veuillez mettre en pause le téléchargement ou essayer plus tardTout en hautAfficher/Masquer menuTotalRésoudre les problèmesEssayez notre nouveau thème Glitter ! Nouveau design optimisé pour les ordinateurs et les appareils mobiles. Aller dans Config - > Général pour changer le thème.Tente de prédire la réussite de la tâche avant le téléchargement complet (plus lent !)Tentative 7zip avec le mot de passe "%s"Tentative de vérification RAREssai vérification SFVEssai de récupération du NZB depuis %sTest de l'état du serveur inexistant %sTentative d'extraction avec le mot de passe "%s"MardiRéglagesTypeDLe chemin UNC "%s" n'est pas autorisé iciINDÉSIRABLEÉchec de récupération de l'URL ; %sL'URLGRABBER A PLANTÉUUencode détecté, seul l'encodage yEnc est compatible [%s]Impossible de lier le port %s sur %s. Un autre logiciel utilise le port ou SABnzbd est déjà en cours d'exécution.Accès non autoriséDébloquerServeur non défini !Erreur inconnue lors du décodage de %sProtocole SSL inconnu: essayez de désactiver SSL ou de vous connecter sur un autre port.Action inconnue : %sÉchec d'authentification inconnu dans le serveur de messagerieDécompresserDécompresser les archives (rar, zip, 7z) à l'intérieur des archives.Arborescence trop profonde dans le fichier compressé [%s]%s fichier(s)/dossier(s) extrait(s) en %sExtractionÉchec de l'extraction, %sÉchec de l'extraction, erreur CRCÉchec de l'extraction, l'archive nécessite un mot de passeLa décompression a échoué, le fichier est trop volumineux pour le système de fichiers (FAT ?)Extraction échoué, le chemin est trop longÉchec de l'extraction, voir le journalÉchec de l'extraction, %s n'a pas été trouvéÉchec de l'extraction, erreur d'écriture ou espace disque insuffisant ?Echec de la tentative de connexion de %sFichier NZB inutilisableFichier RAR inutilisableL'extension indésirable est dans le fichier rar %sExtensions indésirablesMonterMise à Jour disponible!EnvoyerUploader le NZBUploader : .nzb, .rar, .zip, .gz, .bz2Upload en coursTemps de fonctionnementUtiliser les paramètres globaux de l'interfaceUtiliser les tags de l'indexeurUtiliser des noms temporaires pendant le post-traitement. Désactiver lorsque votre système ne le gère pas correctement.Utilisé avant qu'un NZB n'entre dans la file d'attente.Cache utiliséUtile si un serveur de news a plus d'une adresse IPv4/IPv6Dossiers utilisateurClé de l'utilisateurClé de l'utilisateur (obligatoire)Utilisateur connectéUtilisateur connecté à l'interface webLe script utilisateur peut signaler la tâche comme échouéeNom d'utilisateurValeursLa vérification et la réparation ne seront pas possibles.Vérifié avec succès en utilisant des fichiers SFVVérifier les certificats lors de la connexion aux indexeurs et sources RSS utilisant HTTPS.Vérification en coursVérification de la réparationVérification...VersionTrès basseVidéoClassement vidéoAfficher le journal des scriptsVirus/spamPATIENTER %s secAVERTISSEMENT :ATTENTION : la tâche "%s" a été abandonnée à cause d'un fichier RAR chiffré (tous les mots de passe fournis ont été essayés)AVERTISSEMENT : tâche "%s" annulée à cause du classement (%s)AVERTISSEMENT : Le fichier RAR"%s" contient une extension indésirable. Le fichier indésirable est %s ATTENTION : la tâche "%s" a été mise en pause à cause d'un fichier RAR chiffré (tous les mots de passe fournis ont été essayés)AVERTISSEMENT : Tâche "%s" mise en pause à cause du classement (%s)En attenteAvertissementAvertissement: LOCALHOST est ambigü, utilisez une adresse IP numérique.AvertissementsDossier à surveillerIntervalle de scanInterface WebMercrediVérifier chaque semaine les mises à jour de SABnzbd.QuandS'il apparait clairement pendant le téléchargement qu'il manque trop de données, annuler la tâcheLors du tri, utiliser les tags de l'indexeur pour le titre, la saison, l'episode, etc. Sinon, toutes les dénominations seront dérivées du fichier NZB.Lorsque le script de l'utilisateur renvoie un code de sortie "non-zéro", la tâche sera signalée comme échouée.La session expirera quand votre adresse IP changera ou quand SABnzbd sera redémarré.Quel est le pourcentage de la vitesse de la ligne que SABnzbd doive utiliser, par exemple 50Quel script devons-nous utiliser pour les notifications ?Qui doit-on indiquer comme expéditeur de l'email ?WikiNotifications WindowsVitesse d'écritureXAnnéeDossiers Année-MoisVous pouvez définir les droits d'accès pour les systèmes en dehors de votre réseau local. Requiert la liste des plages de réseaux locaux à définir.Vous devez activer JavaScript pour que Plush puisse fonctionner !Vous devez définir une bande passante maximale avant de pouvoir définir une limite de bande passanteVotre version de UNRAR est %s, nous recommandons la version %s ou plus.
Votre fichier de mot de passe contient plus de 30 mots de passe. Tester tous ces mots de passe prend beaucoup de temps. Essayez de n'y lister que les mots de passe utiles.Votre clé API Pushbullet personnelle (obligatoire )[%s] Erreur "%s" lors de la concaténation des fichiers[%s] Erreur "%s" lors de l'extraction des fichiers RAR[%s] %s fichiers fusionnés[%s] Pas de fichiers par2[%s] PAR2 a reçu des paramètres incorrects, vérifiez dans Configuration-> Paramètres Switches[%s] Contrôle rapide OK[%s] La vérification RAR a échoué: %s[%s] Réparé(s) dans %s[%s] Vérifié dans %s, tous les fichiers sont corrects[%s] Vérifié dans %s, réparation nécessairemodule _yenc... Introuvable!articlesaudioLettre Capitaleéffacerjjourjoursdésactiver le serveurrejetéactiver le serveurfichierhheureheuresmots-clésrestantmmanuelminmin.minsnon installédenonouiouou moinspagebinaire par2... Introuvable!protégé par mot de passesecsecondesvoir le journalspamtexteinconnubinaire unrar... Introuvable!binaire unzip... Introuvable!vidéosemaineSABnzbd-2.3.2/locale/he/LC_MESSAGES/SABnzbd.mo0000644000000000000000000030050213217005256016370 0ustar 00000000000000x#GoGd HrI lJyKmLWM*nM'MMMM N/N>N^N ~NNN@OHOOOWO_OgO1zOOO*OOAPYP?PQ"Q2Q:QRJQ[QQ RR#R>R[R#xR$RR RR.R: S'GS'oSSSSSS S S SSSTTT' TJHTtTU/UMUcUvU}UU UUU)U*U 'V 5V?VSVfVoVwV }VV/VhV *W6WW*AXlXnXsX%zX#XXX XY Y'Y\.Y YYZ.Z5Z UZvZ ZZZZ! [6,[-c["[[["[6\;\ W\b\Gk\l\< ]]].v]'] ]]]^ ^S!^u^ ^^^^.^"^8_G_\_d_s__ __U_` ` &`4`N` f`#p``` ```*`a6*aaasaza |aa a3a a a a aabb-b@bHb\b`b gbrb bb(bb b-cl l ll l ll(l.l)%m&Om,vm<m&mn"n'5n]nonnn n n&n-oHoeoo ooo o ooopp *p8pAp\pcp~pp%p!pp+q x/x x xx'xxy )y 3y>y]yoby yy yyzz%z;zMz `zz zzz;z>z-/{9]{{ {{ {{{6{|G||"|}}E"}Dh} }}Q~,c~~~%~#~2@R*<2%ԁFAY'p1H9; Ӄ ރ} ny *%Ą%.5H ~HnمHemqc$Hoч]A) ɈԈۈ 28 @J$]0,]qa  # 1 <G NXiz‹Njߋ# 3= V1a" + ,'': b pz/͎; /9Yci"͏#A,V*3Ő!1!S"u% " 1?PW4j  *͒   "(, U_pғ -E`vM}˔##%4ZRi<"@Ppj%#I_-g× ܗ %7=QWl ~ Ҙ  !,5<D əؙ +-Hhl Û֛  9 C OZ tŜ ؜ 2 4> S `l)0Ν(F bnt Ҟ %>Zqz !ʟ$;QFfH  '4O`p.> my  Ƣע# #*,Anv ¤ ˤ4 !+ 0;R3e3.ͥ)Bb!s  -֦,(1Zi$x!ק"-&P:wo)*T3k Ʃ өݩ  " ,"6Yl u 'Ȫ(ͪ>.5d i u//--&=&d$$3լ3 1=1o íRϭ " - 8EUfm Ǯή'D I/S   ӯ߯"Ͱα25APS>k= M+A mWwϴ,t > ͶӶ"!A'imv |EYx.ʸ!(-/NWo7a08JJj-Ⱥ/-J jt-6ӻ" -#G.k"ϼ$/ 6 A blsb$ /:: u#"Ҿ-%3LY  οֿ߿   _"0E^/X:  %CRHwUMi=0!&HM cqsxv1E4Bz+E#q)J1&El&'   ' 1?DFKQZ_ahlq v  "(-Q66Zm00$*,O>|!';(O)x  bG`>{"C!XOV n{| A)!0-R5 .L 4X=  +;L hs>jG8"Hk" I>K"  9)c"K (&(O0o $ mUe# @-K+y+8/ 3:6n2PV)2 >>eR- wtK X-n; !%.hKL:\_&%;$Q v$2; O$Z 3$::'uS &/II ,*A)U F/#/SH +3x6'?g-v= E"hHq,$/:T/2ED8}  2&-QT 5 7 O \i  J)5<&r 1.A#U:y '%M V d A(`"<%E " /T<  =>"4a1<P9V4820+c+)EL?.) ); K&V}+  1,!5W p(:*< ,] ',$ %=F%G#&(=f+)&%')Q p })"     : C #]   ] & 29 2l 0     Q  i 2t Q  y  / * E i=     +  !5 ERb q {.mTc N1B`o~/$Af'z :&5<r y3GM 3ZG @_e>`]^F8/*h$.Q)RG||3CG;t$<#aF  [N&^ w    ! @ >!7F!~! !! !I!"-"h<"".1#`#i#+###Z$j$T%y%/x&& & && & ''*'0'H'O'X'p'='*'' ' ((J())5)xD) )))4) ** 0* <* H* S*a* u*'** **++"+ 2+ >+_+z+++&++5+5,H,.\,,, [-f- x-C----.)..@. o. |. .>.".*. ///Y8/ /%///1s020W0D01;u11=12 .292"S2*v2-2,22/ 3 =3H3f333333 33M3 L4Y4 k4v4?444445 505N5`5y55555 6,62A6#t626266 7K$7p77-77/7!8l98I8838+-9Y9<k99999,:(::B: 1;<; W; b;#o; ;;;;;;< <*<1<K<+c<< <<< <!< = 8=C=L=Kb==0===>)>>>T> Y>d>|>*>>$>$> ??#(?L?]?{f?$@AA-A*MAxAAAA8AAA B B *B*8B cB BBBB B BFBDCMC eCqC-C-C=CJ$DoDxDDDD DDDEE'E#FE#jEE EE2E#E2F2KF~F FF FFF!F5GMFG5GGG!GH2HYOHSHHI$I7I)HIrIII'III!J J*JJ JKKK/K8K QK"\K-K K K&K8K#L2L NLYLGkL M MM;M :NENLN^NzNJN=N<OYO0xO"OO-O PP3P/:P=jP<P<P"Q2Q.DQsQ3QQQQR-(R/VReR RRUSSBSG`7`O`aea],bSbbgb1XccWcc2ddePeoe ee#eeff2f*fagggggg]h$h"i5iMi;ki(ii iii*i$j$6j[j9xjjqnBn3n'oFo0eo"o ooo o"opp1-p _pp/qEqQ]qqqqq)rH:rr r5r-rms ps{s sss sssst ,t8tDthumuDu 9v DvVOv vv6vww<&wcwmjwwwx`xVXy>y3y "z-zBzZz\zczzAA{e{f{P|4}3S}5}}}j}#`~+~~5~*~"% HU\v}-6?H M[#` ǀ΀Ӏ#$  .9 SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!
If authentication is enabled, you will need to login again.NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAdvancedAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")All usernames, passwords and API-keys are automatically removed from the log and the included copy of your settings.Allow load-balancingAllow load-balancing with optimization for IPv6Allow proper releasesAlso test releasesAlwaysApplication TokenApplication token (required)Apply filtersApply to SelectedAprilAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAugustAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically delete completed jobs from History. Beware that Duplicate Detection and some external tools rely on History information.Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseBypass series duplicate detection if PROPER, REAL or REPACK is detected in the download nameCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryCategory folder cannot be a subfolder of the Temporary Download Folder.Certificate hostname mismatch: the server hostname is not listed in the certificate. This is a server issue.Certificate not valid. This is most probably a server issue.Certificate verificationChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking extra filesChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentCompact layoutComplete FolderComplete folder speedCompletedCompleted Download FolderCompleted Download Folder %s is on FAT file system, limiting maximum file size to 4GBConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCorrupt RAR fileCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecemberDecoder failure: Out of memoryDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDetect identical NZB files (based on items in your History or files in .nzb Backup Folder)Detect identical episodes in series (based on "name/season/episode" of items in your History)DeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDirect UnpackDirect Unpack was automatically enabled.Disable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDo not keep any completed jobsDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDownloads will not unpacked.DualView1DualView2Duplicate NZBE.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: File too large for filesystem (%s)ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmergency expireEmergency retryEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Indexer IntegrationEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable notification scriptEnable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExecutes a custom scriptExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra history columnExtra queue columnExtracting...FILTEREDFail job (move to History)FailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send Windows notificationFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: Failing duplicate NZB "%s"FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFebruaryFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File not on serverFile setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user scripts.Folder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.For unreliable servers, will be ignored longer in case of failuresForceForce DisconnectForce DownloadForcing disconnectFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom Show SxxEyyFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGenerate new self-signed certificate and key. Requires SABnzbd restart!Glitter has some (new) features you might like!Go to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHTTPS certificate verificationHelpHelp us translate SABnzbd in your language!
Add untranslated texts or improved existing translations here:Hibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory RetentionHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How many seconds your notification will continue to be retriedHow much can be downloaded this month (K/M/G)How often (in seconds) the same notification will be sentIDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If the SABnzbd Host or Port is exposed to the internet, your current settings allow full external access to the SABnzbd interface.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIncrease performance by forcing a lower SSL encryption strength.Indexer Categories / GroupsIndexer id (%s) not found for ratings fileIndexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to "Indexer Categories / Groups" to match more categories. Use commas to separate terms. Wildcards in the terms are supported.
More information can be found on the Wiki.Indexers can supply rating information when a job is added and SABnzbd can report to the indexer if a job couldn't be completed.IndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid par2 files or invalid PAR2 parameters, cannot verify or repairInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIssuesIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.JanuaryJob "%s" is probably encrypted due to RAR with same name inside this RARJob "%s" is probably encrypted: "password" in filename "%s"Job Name as FilenameJob failedJob finishedJobsJobs will start unpacking during the downloading to reduce post-processing time. Only works for jobs that do not need repair.Join filesJoiningJulyJuneKeep all jobsKeep completed jobs maximum number of daysKeep loose downloads in extra foldersKeep maximum number of completed jobsLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!Location for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLog inLog outLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMarchMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMayMeaningMinimalMinimal: when SSL is enabled, verify the identity of the server using its certificates. Strict: verify and enforce matching hostname.Minimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateModule subprocessww missing. Expect problems with Unicoded file and directory names in downloads.MondayMonthMoreMore thumbs down than upMovie NameMovie SortingMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelMultiPar binary... NOT found!Multicore Par2NZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNone of the enabled servers have the 'Default' category selected. Jobs in the queue that are not assigned to one of the server's categories will not be downloaded.NormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification ScriptNotification Sent!Notification script "%s" does not existNotificationsNotifyOSDNovemberNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOctoberOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly external access requires loginOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOriginal Job NameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPROPAGATING %s minPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause jobs with categoryPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.Pre-queue script marked job as failedPre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressPropagation delayProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge NZBs on the current pagePurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionPython script "%s" does not have execute (+x) permission setQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRAR files failed to verifyRAR files verified successfullyRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemember meRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRemoving jobRemoving jobsRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...Restore DefaultsResultResumeResume high prioirty jobsResume jobs with categoryResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABYenc disabled: no correct version found! (Found v%s, expecting v%s)SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyencSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.SABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSSL CiphersSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScript returned exit code %s and output "%s"ScriptsScripts FolderSearchSeason NumberSecure (SSL) connections from SABnzbd to newsservers and HTTPS websites will be encrypted, however, validating a server's identity using its certificates is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-date local CA certificates are required.Secure connection to serverSecuritySelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeperate multiple URLs by a commaSeptemberSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s uses an untrusted certificate [%s]Server %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer could not complete requestServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeed up repairs by installing multicore Par2, it is available for many platforms.SpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...StrictSubjectSubmitSubmitted. Thank you!SundaySupport the project, Donate!Suspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETabbed layout
(separate queue and history)Tag jobTaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key provides identity to indexer. Check your profile on the indexer's website.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis prevents multiple repair runs by downloading all par2 files when needed.This server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying RAR-based verificationTrying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUUencode detected, only yEnc encoding is supported [%s]Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running.Unauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown SSL protocol: Try disabling SSL or connecting on a different port.Unknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, file too large for filesystem (FAT?)Unpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unsuccessful login attempt from %sUnusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UploadingUptimeUse global interface settingsUse tags from indexerUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User logged inUser logged in to the web interfaceUser script can flag job as failedUsernameValuesVerification and repair will not be possible.Verified successfully using SFV filesVerify certificates when connecting to indexers and RSS-sources using HTTPS.VerifyingVerifying repairVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen sorting, use tags from indexer for title, season, episode, etc. Otherwise all naming is derived from the NZB name.When the user script returns a non-zero exit code, the job will be flagged as failed.When your IP address changes or SABnzbd is restarted the session will expire.Which percentage of the linespeed should SABnzbd use, e.g. 50Which script should we execute for notification?Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou can set access rights for systems outside your local network. Requires List of local network ranges to be defined.You must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your password file contains more than 30 passwords, testing all these passwords takes a lot of time. Try to only list useful passwords.Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] RAR-based verification failed: %s[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2017-12-06 19:50+0000 Last-Translator: ION IL Language-Team: Hebrew MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:30+0000 X-Generator: Launchpad (build 18511) .%s-אינו יכול למצוא את קבצי ממשק הרשת שלו ב SABnzbd
.אנא התקן את התכנית שוב

אחרת SABnzbd גילה נתונים שמורים מגרסת SABnzbd
.אבל אינו יכול להשתמש מחדש בנתונים של התכנית האחרת

.אתה אולי תרצה לסיים את התור שלך תחילה עם התכנית האחרת

."--clean" לאחר מכן, התחל תכנית זו עם האפשרות
!זה ימחק את התור וההיסטוריה הנוכחיים
."%s" קרא את הקובץ SABnzbd .חסר sqlite3.dll גילה שהקובץ SABnzbd

.מספר סורקי-נגיפים ירודים מסירים קובץ זה
.והתלונן למוכר סורק-הנגיפים שלך SABnzbd אנא בדוק את סורק-הנגיפים שלך, נסה להתקין מחדש את

.עבור שרת הרשת הפנימי שלו tcp/ip צריך פתחה חופשית של SABnzbd
.פתחה %s על %s נוסתה, אך היא אינה זמינה
.כבר רץ SABnzbd איזשהי תוכנה אחרת משתמשת בפתחה או

.עם מספר פתחה אחר SABnzbd אנא הפעל מחדש את .צריך כתובת מארח תקפה עבור שרת הרשת הפנימי שלו SABnzbd
.ציינת כתובת בלתי תקפה
ו-0.0.0.0 localhost ערכים בטוחים הם

.עם כתובת מארח תקינה SABnzbd אנא הפעל מחדש את .גרסה 2 או (לבחירתך) כל גרסה שהיא מאוחרת יותר GNU מגיע בהחלט ללא אחריות. זו תוכנה חינמית, ואתה מוזמן להפיצה מחדש תחת תנאים מסוימים. היא ברשיון תחת רשיון ציבורי כללי של SABnzbd הצפנה בלתי ידועה <- %sחסר מכל השרתים, משליך <= %sל-%s מאמרים יש כפילויות בלתי-תואמות%s מאמרים עוותו%s מאמרים היו חסרים%s מאמרים הוסרו%s שגיאת גישה :%s ספרייה%s קבצים ב %s%s אינו ערך אוקטלי נכוןאינה כתובת דוא"ל תקפה %s%s חסרים פותר כתובת 
.הסתיים SABnzbd כיבוי
.המתן בערך 5 שניות ואז לחץ על הכפתור למטה

רענן
+ ניפוי תקלים+ מידע+מחיקה+תיקון+פריקה.nzb תיקיית גיבוי0 הוא העדיפות הגבוהה ביותר, 100 הוא העדיפות הנמוכה ביותר1x05 תיקיית פרק1x05 תיקיית עונהאינה שלמה, לא יכול לפרוק "%s" ZIP7 ערכת!בינארי... לא נמצא za7
אם אימות מאופשר, תצטרך להיכנס שוב.הערה: תיקיות יווצרו באופן אוטומטי בעת שמירה. אתה יכול להשתמש בנתיבים מוחלטים כדי לשמור מחוץ לתיקיות ברירת המחדל!SABnzbd נתונים לא יועברו. דורש הפעלה מחדש שלגיל(ללא תצורה) APIAPI מפתחAPI של מפתח QR קודמתצורה->כללי בתכנית הצד השלישי שלך api-אינו נכון, השתמש במפתח ה API מפתח:מתצורה->כללי לתוך תכנית הצד השלישי שלך api-חסר, אנא הכנס את מפתח ה API מפתח:Prowl עבור API מפתחבטלבטל אםבטל עבודות שאינן יכולות להיות שלמותבוטל, לא יכול להיות שלםבוטל, הצפנה התגלתה(%s) בוטל, מסנן מידרג הותאםבוטל, סיומת בלתי רצויה התגלתהקבלגישה נדחתהפעולה.הורדה בהתאם לכללי הסינוןRAR פעולה כאשר סיומת בלתי רצויה מתגלה בקבצימוצפן מורד RAR פעולה כאשר קובץפעולה כאשר סיומת בלתי רצויה מתגלהפעולותהוסףהוסף קובץNZB הוסףNZB הוסף קבצי הוסף תזמוןהוסף שרתהתווסף NZBתיקייה מינהליתמתקדםמדורים מושפעיםגילהכל.כל הקבצים יעברו לתוך תיקייה יחידה.("כל כתובות הרשת המקומית מתחילות במקדמים אלו (לעיתים "192.168.1.מוסרים באופן אוטומטי מהיומן ומהעותק הכלול של ההגדרות שלך API-כל שמות המשתמש, הסיסמאות ומפתחות ההתר איזון-עומסIPv6 התר איזון-עומס עם ייעול עבורהתר שחרורים תקיניםגם שחרורי בחינהתמידאסימון יישום(אסימון יישום (דרושהחל מסנניםהחל לנבחריםאפריל?SABnzbd האם אתה בטוח שברצונך להפעיל מחדש את?SABnzbd האם אתה בטוח שברצונך לכבות אתהאם אתה בטוח?טיעוניםמגבלת מטמון מאמריםמזהי מאמרלפחותלכל היותרשמעמידרג שמעאוגוסט.אימות נכשל, בדוק שם משתמש/סיסמה:אימות חסר, אנא הכנס שם משתמש/סיסמה מתוך תצורה->כללי לתוך תכנית הצד השלישי שלךהמשך באופן אוטומטי.השהה באופן אוטומטי כששטח פנוי הוא מתחת לערך זה
"בבתים, עקוב באופן רשותי אחר ק,מ,ג',ט. לדוגמה: "800מ" או "8ג.מחק באופן אוטומטי עבודות שלמות מההיסטוריה. שים לב ששימור כפול ומספר כלים חיצוניים מסתמכים על מידע היסטוריה.(מיין פריטים באופן אוטומטי לפי גיל (ממוצעבהקודםגיבויPushbullet (%s): %s-תגובה רעה מPushover (%s): %s-תגובה רעה מב-%s:%s %s תזמון גרוע%s-נוצר באופן גרוע ב yEnc מאמררוחב פסחסום רענונים בריחוףתחתיתעיין.מתגלים בשם ההורדה REPACK או PROPER, REAL עקוף גילוי כפילויות סדרה אםדגם יע''ם.הטמן מאמרים בזיכרון כדי להפחית גישת דיסק
"בבתים, עקוב באופן רשותי אחר ק,מ,ג'. לדוגמה: "64מ" או "128מ(%s) מאמרים %s מוטמניםביטול%s לא יכול לשנות הרשאות של%s [%s] לא ניתן להתחבר לשרת%s תיקייה %s לא יכול ליצור%s לא ניתן ליצור קובץ גיבוי עבור%s לא יכול ליצור את הספרייה%s לא יכול ליצור תיקייה סופית%s לא ניתן ליצור קובץ זמני עבור%s-לא ניתן למצוא תבניות דוא"למנסה תבנית תקנית ,%s :לא ניתן למצוא תבניות רשתלא היה ניתן להפעיל את הדפדפן, כנראה שהוא לא נמצאSABHelper לא ניתן לגשת אל השירותלא יכול לקרוא את %s%s לא ניתן לקרוא את התיקייה המושגחתלא ניתן לשלוח, נתונים דרושים חסרים!לא ניתן לכתוב במסד-נתונים של היסטוריה, בדוק זכויות גישה%s קובץ INI לא ניתן לכתוב אלמדוריםמדור.תיקיית מדור אינה יכולה להיות תת-תיקייה של תיקיית ההורדות הזמניות.שם מארח של האישור אינו תואם: שם המארח של השרת אינו מופיע ברשימה באישור. זו סוגית שרת.אישור אינו תקף. קרוב לוודאי שזו סוגית שרתוידוא אישורשינויים לא נשמרו, ויאבדו.!SABnzbd שינויים ידרשו הפעלה מחדש שלסמן הכלבדוק לפני הורדהבדוק אחר שחרור חדשבודקבודק קבצי תוספת!מרווח בדיקה (בדקות, לפחות 15). אינו פעיל כשאתה משתמש במתזמן.בחר עוררשימת ניקוי.נכשל %s ניקוי שלנקהנקה מוניםלחץ על הכפתור חזור על בחינה למטה כדי לקבוע.לחץ כדי לבחון את הפרטים שהוכנסו.SABnzbd סגירה של חלונות/לשוניות כלשהם/כלשהן לא תסגור אתרשימה מופרדת בפסיקיםהערפריסה צמומהתיקייה שלמהמהירות תיקיית שלמיםהושלםתיקיית הורדות שלמותהמגבילה גודל מרבי של קובץ אל 4 ג"ב ,FAT היא במערכת קבצים %s תיקיית ההורדות השלמותהגדרקובץ תצורהתצורהאשר מחיקות היסטוריהאשר מחיקות תורמאושר%s=נכשלה, הודעה %s@%s התחברות אל!חיבור מוצלח!חיבור נכשלחיבוריםרוחב מכלפגום RAR קובץ(%s) לא היה ניתן לקבוע תוצאת חיבור%s לא היה ניתן לפרוק את.לא היה יכול לכתוב. בדוק שהספרייה ניתנת לכתיבהתזמונים נוכחייםמותאםמכפוליומיתיקיות יומיותמסד-נתונים היסטוריה פגום, נוצר תחליף ריקלוח מחווניםמיון תאריכיםתסדיר תאריךיום בחודשעשורדצמברכישלון מפענח: אין זיכרוןנכשל %s פענוחברירת מחדלתיקיית יסוד ברירת מחדלמחקמחקמחק הכלמחק שלמיםמחק נכשליםמחק לאחר הורדה?למחוק את כל הפריטים השלמים מההיסטוריהלמחוק את כל הקבצים שהורדו?למחוק את כל הפריטים מהתור?למחוק את כל הפריטים הנכשלים מההיסטוריה?!נכשלה %s מחיקתגלה הורדות כפולותגלה פרקים כפולים בסדרות(.nzb זהים (על סמך פריטים בהיסטוריה שלך או קבצים בתיקיית גיבויים של NZB גלה קבצי(גלה פרקים זהים בסדרות (על סמך "שם/עונה/פרק" של פריטים בהיסטוריה שלךהתקןהתקן אליו הודעה תישלחהתקן(ים)התקנים אליהם הודעה תישלחפריקה ישירה.פריקה ישירה אופשרה באופן אוטומטיהשבת ניהול מיכסהמושבתKEY-ו CERT בגלל קבצים חסרים של HTTPS השבית אתהשלך.כאשר התור ריק או מושהה Usenet התנתק משרת(י)התנתק בתור ריקהתראות דיסק מלא%s שגיאת דיסק ביצירת קובץדיסק מלאדיסק מלא! מאלץ השהיה.SFV בצע וידוא נוסף המבוסס על קבצי%s אין אימות תקף עבור ההזנהאל תשמור עבודות שלמות כלשהן?האם המיכסה מתאפסת כל יום, שבוע או חודש.%s אנו ממליצים לנסות את ?usenet אין לך ספקלמטההורדההורדה הושלמהתיקיית הורדותהורדה נכשלהpar2 הורד את כל קבציהורדה נכשלה - לא בשרת(ים) שלךמהירות תיקיית הורדותהורדה עשויה להיכשל, רק %s מתוך %s דרושים זמיניםהוּרדלשנייה %sB הורד תוך %s בממוצע שלמורידהורדות.הורדות לא ייפרקותצוגה כפולה 1תצוגה כפולה 2NZB שכפללדוגמהלדוגמה 8 או 20מוצפןשגיאה:%s :שגיאה"%s"-נכשל ב CRC :שגיאה(%s) שגיאה: קובץ גדול מדי עבור מערכת הקבצים(%s) שגיאה: נתיב ארוך מדי"%s" שגיאה: לא היה ניתן למצוא את(%s) שגיאה: שגיאת כתיבהזמן משוערערוךNZB ערוך פרטיולא השהה אםדוא"להתראת דוא"ל בעת השלמת עבודהמקבל דוא"לשולח דוא"ל!דוא"ל נשלחתיקיית תבניות דוא"ל.כתובת דוא"ל לשלוח אליה את הדוא"לדוא"ל הצליחחירוםתפוגת חרוםניסיון חוזר חרוםריק%s ריק NZB קובץ(%s) ריקה נמצאה RSS כניסתאפשר7zip אפשראפשר מיון תאריכיםאפשר סינוןGrowl אפשרHTTPS אפשראפשר מיזוג מדדןאפשר מיון סרטיםNotifyOSD אפשרProwl אפשר התראותPushbullet אפשר התראותPushover אפשר התראותSFV אפשר בדיקות מבוססותאפשר מיון טלוויזיהzip אפשר חילוץWindows אפשר התראות.HTTPS אפשר מתן גישה אל הממשק מכתובתאפשר שינוי שם תיקייה.אפשר עבור פחות שימוש בזיכרון. השבת כדי למנוע מעבודות איטיות לחסום את התוראפשר תסריט התראותאפשר ניהול מיכסהאפשר פריקה נסיגתיתמאופשר.סיום הנתיב עם כוכבית * תמנע יצירת תיקיות עבודההכנס כתובתשם פרקמספר פרקשם.פרקשם_פרקשגיאה%s שגיאה "%s" בזמן הרצת איחוד_קבצים ב%s על ערכת par2_repair בזמן הרצת "%s" שגיאה%s על rar_unpack שגיאת "%s" בזמן הרצת%s על unzip() שגיאת "%s" בזמן הרצת%s על ערכת par2_repair בזמן הרצת %s שגיאת.שגיאה %s: אתה צריך לספק שם משתמש וסיסמה תקפיםSSL נכשל ביצירה של מפתח ואישור של(%s) שגיאה בהשגת מידע טלוויזיה%s שגיאה ביבואהתגלה קובץ פגום ,%s שגיאה בטעינת%s שגיאה בהסרת(%s) שגיאה בהסרת תיקיית עבודה"%s" אל "%s" שגיאה בשינוי שםמסיר ,%s שגיאה בזמן הוספתשגיאה בזמן כיבוי מערכתשגיאה בלבד.שגיאה: אורך הנתיב צריך להיות מתחת אל %s.שגיאה: התור אינו ריק, לא יכול לשנות תיקייהשגיאה: מפתח לא נכון של שיחשגיאה: מפתח דרוש של שיחשגיאות/אזהרותהכלדוגמהמבצע תסריט מותאם אישיתSABnzbd-צא מסיומתגישת אינטרנט חיצוניתנוספים PAR2 משתניעמודה נוספת של היסטוריהעמודת תור נוספתמחלץ...מסונןהכשל עבודה (העבר להיסטוריה)נכשל%s נכשל בכניסה לשרת(%s) נכשל בעשיה%s אל %s נכשל בהעברתנכשל באימות שרת הדוא"לנכשל בסגירת מסד-נתונים, ראה יומןנכשל בסגירת חיבור דוא"ל%s :עבור מונח חיפוש regex נכשל בליקוטנכשל בהתחברות לשרת דוא"לנכשל בחריפת מערכת%s נכשל ביבוא %s קבצים מ%s :מהסיבה %s@%sנכשל באתחולTLS נכשל ביזימת חיבורנכשל בהעברת קבצים%s אל %s :נכשל בשינוי שם של קובץ דומה%s אל %s:נכשל בשינוי שם(%s) לאחר קדם-בדיקה NZB נכשל בהפעלה מחדש של%s: %s-מ RSS נכשל באחזורProwl נכשל בשליחת הודעתWindows נכשל בשליחת התראתנכשל בשליחת דוא"לpushbullet נכשל בשליחת הודעתpushover נכשל בשליחת הודעתנכשל בהיכוננות מערכתנכשל בהתחלת ממשק רשתנכשל בהתחלת ממשק-רשת: "%s" NZB נכשל בשכפולכישלוןtempfile.mkstemp-כישלון בשגיאה חמורהשגיאה חמורה במצב שמירהAssembler-שגיאה חמורה בפברוארהזנהמשוךמכתובת NZB משוךמושך...מושך %s גושים...מושך גושים נוספיםריק, מדלג %s הקובץסיומת קובץ.מוצפנים RAR קובץ המכיל את כל הסיסמאות שינוסו על קבצינכשל %s איחוד קבצים של.HTTPS שם קובץ או נתיב אל אישור.HTTPS שם קובץ או נתיב אל שרשרת.HTTPS שם קובץ או נתיב אל מפתחקובץ לא על השרתערכת קבציםשם קובץמסנן.(סנן החוצה קבצי דוגמית (לדוגמה דוגמיות וידאוראשון.תיקייה המכילה תסריטי משתמש.תיקייה המכילה תבניות דוא"ל מוגדרות ע"י משתמש.nzb תיקייה לניטור אחר קבצי
.nzb אחר קבצי tar.gz-ו rar, zip סורק גם ארכיוניתיקייה/נתיבתיקיות.עבור דוא"ל מאומת, שם חשבון.עבור דוא"ל מאומת, סיסמה.Windows עבור שרתים: וודא שהשמות תואמים עםעבור שרתים בלתי מהימנים, ייתקל בהתעלמות במקרה של כישלונותאילוץאלץ ניתוקאלץ הורדהמאלץ ניתוק.nzb, .rar, .zip, .gz, .bz2 :תסדיריםפורוםפנוי (זמני)שטח פנויתדירותיום שישיShow SxxEyy-מSxxEyy-מAPI מלאממשק רשת מלאעזרה נוספת יכולה להימצא בג''בכלליחולל מפתח חדש!SABnzbd חולל אישור ומפתח חדשים חתומים-עצמית. דורש הפעלה מחדש של!יש מספר מאפיינים (חדשים) שאתה עשוי לאהוב Glitter-לSABnzbd עבור אללך לאשףGrowlאינן יכולות להיות אותו דבר HTTPS-ו HTTP פתחות שלHTTPS אישורHTTPS אישורי שרשרתHTTPS מפתחHTTPS פתחתHTTPS וידוא אישורעזרה!לעברית SABnzbd עזור לנו לתרגם את
הוסף מלל לא מתורגם או שפר תרגומים קיימים כאן:חרוף מחשבהסתר אפשרויות עריכההסתר פרטיםהסתר/הראה קבצים שלמיםגבוהההיסטוריההעבר להיסטוריה 10 פריטים אחרוניםשימור היסטוריהמגבלת פריטי היסטוריהכדי לבחור טווח shift החזק את מקשביתדף הביתמארח.צריך להאזין אליו SABnzbd-מארח ש(!כמה זמן או עד מתי תרצה להשהות? (באנגליתכמה שניות ההתראה שלך תמשיך להיות מנוסה שוב('כמה ניתן להוריד החודש (ק/מ/גבאיזו תדירות (בשניות) אותה ההתראה תישלחמושבתבלתי שלםIONice משתניIPv6 כתובתIRCסרק.HTTPS אם ריק, הפתחה התקנית תאזין רק אל.SABnzbd חשופים לאינטרנט, ההגדרות הנוכחיות שלך מאפשרות גישה חיצונית מלאה אל ממשק SABnzbd אם המארח או הפתחה של.אם אתה מקבל את הודעת השגיאה הזו שוב, אנא נסה מספר שונה
התעלם מדוגמאותהתעלם מתיקיות כלשהן בתוך ארכיונים"%s" כפול NZB-מתעלם מב.במקרה של "השהיה", תצטרך לקבוע סיסמה ולהמשיך את העבודה!המסך יעלם באופן אוטומטי SABnzbd במקרה של הפעלה מחדש שלבתיקיות.תידרש לך גישה אל ספק. ספק שירותי האינטרנט שלך עשוי לספק לך גישה, אולם מומלץ ספק פרימיום usenet-על מנת להוריד מהזנה בלתי תואמתקובץ תור בלתי תואם נמצא, לא יכול להמשיךתיקייה בלתי שלמה%s בלתי שלם NZB קובץרצף בלתי שלם של קבצים ברי-איחוד"%s" לא נכון RSS תיאור הזנתמשתנה לא נכון%s: %s ערך לא נכון עבור%s סיסמה מוצפנת באופן שגוי.חלש יותר SSL הגבר ביצועים ע"י אילוץ חוזק הצפנתמדורים / קבוצות של מדדןלא נמצאה עבור קובץ מידרגים (%s) זהות מדדןינסה להתאים למדורים המוגדרים למטה. בנוסף, אתה יכול להוסיף תנאים אל "מדורים/קבוצות של מדדן" כדי להתאים עוד מדורים. השתמש בפסיקים כדי SABnzbd אשר NZB-מדדנים יכולים לספק מדור בתוך ה.להפריד תנאים. תווים כללים נתמכים בתנאים
.עוד מידע יכול להימצא בוויקייכול לדווח למדדן במקרה שעבודה לא יכלה להישלם SABnzbd-מדדנים יכולים לספק מידע מידרג כאשר עבודה מתווספת ואחסון במדדמדלג ,%s בלתי תקף NZB קובץ (סיבה=%s שורה=%s)%s הצפנה בלתי תקפה של תבניות דוא"לבלתי תקפים, לא יכול לוודא או לתקן PAR2 בלתי תקפים או פרמטרי par2 קבצי.כתובת שרת בלתי תקפהפרטי שרת בלתי תקפים%s התחברות שלב בלתי תקפה בהיסטוריה עבורהפוךסוגיות.כאשר הוא רץ ברקע SABnzbd מומלץ ללחוץ לחיצה ימנית וליצור סימנייה למיקום זה ולהשתמש בסימנייה זו כדי להשיג גישה אלינוארזה RAR עם אותו השם בתוך RAR כנראה מוצפנת עקב "%s" העבודה"%s" כנראה מוצפנת: "סיסמה" בשם הקובץ "%s" העבודהשם עבודה בתור שם קובץעבודה נכשלהעבודה הסתיימהעבודות.עבודות יתחילו להיפרק במהלך ההורדה כדי להפחית זמן בתר-עיבוד. עובד רק עבור עבודות שאינן צריכות תיקוןאחד קבציםמאחדיולייונישמור את כל העבודותשמור מספר ימים מרבי של עבודות שלמותשמור הורדות רפויות בתיקיות נוספותשמור מספר מרבי של עבודות שלמותשפהאחרוןאזהרות אחרונותהפעל דפדפן באתחול.SABnzbd הפעל את דפדפן ברירת המחדל בעת התחלתהגבל מהירותקישוריםexe, com או exe :רשום את כל הסיומות הבלתי רצויות. לדוגמה.רשימת סיומות של קבצים שצריכים להימחק לאחר הורדה
nfo, sfv או nfo :לדוגמהרשימה של טווחי רשת מקומיתטועןנכשלה %s טעינת%s נכשלה עם שגיאה %s טעינתמקומית IPv4 כתובת!אחסון מקומי (עוגיות) מושבת בדפדפן שלך, קביעות ממשק יאבדו לאחר שתסגור את הדפדפן.מיקום עבור מסד-נתונים היסטוריה ומנהלן תור
.ניתן לשינוי רק כאשר התור ריק.SABnzbd מיקום של קבצי יומן עבור
!SABnzbd דורש הפעלה מחדש של.מיקום לאחסון הורדות שהסתיימו, מעבודות במלואן
.ניתן להשתלט ע"י מדורים מוגדרים ע"י משתמש.מיקום לאחסון הורדות בלתי מעובדות
.ניתן לשינוי כאשר התור ריק.יאוחסנו .nzb מיקום שבו קבציתיקיית יומןהתחברהתנתקרושם ביומן..SABnzbd אבד חיבור אלנמוכהרישיות קטנהמ"בWindows עשה תואםמרץתואםמהירות מרביתמהירות קו מרביתמספר מרבי של ניסיונות חוזרים לשרתניסיונות חוזרים מרבייםמאימשמעותמזערימאופשר, וודא את זהות השרת ע"י שימוש באישוריו. קפדני: וודא ואכוף שם מארח תואם SSL מזערי: כאשרשטח פנוי מזערי עבור תיקיית הורדות זמניותמפתח חסר של שיחמאמרים חסריםבינונית.של קבצים וספריות בהורדות Unicode חסר. צפה לבעיות עם שמות subprocessww פירקןיום שניחודשעודיותר אגודלים למטה מאשר למעלהשם סרטמיון סרטיםשם.סרטשם_סרטמעבירמעביר...רב-תפעוליםתווית מרובה חלקים!בינארי... לא נמצא MultiParPar2 מרובה-ליבותNZB מפתחהתווסף לתור NZBשםDNS שם שרת / חיפושמתן שמותאף פעםשחרור חדש %s זמין בשחרור חדש זמיןהבאNice משתניאין גישהלא נמצאו תבניות דוא"לאין תיקיותאין בתר-עיבוד בגלל וידוא כושללא ניתנו נמענים, לא נשלח דוא"לאין תוצאותלא נמצאה שיטת אימות הולמתללא.לאף אחד מהשרתים המאופשרים אין את המדור 'ברירת מחדל' כנבחר. עבודות בתור שאינן מוקצאות לאחד ממדורי השרת לא יורדורגילהבלתי תואםלא זמין!אין מספיק שטח פנוי כדי להשלים הורדותלא בשימושלא נבחר שום דבר!מרכז ההתראותתסריט התראות!התראה נשלחהאינו קיים "%s" תסריט התראותהתראותNotifyOSDנובמבר.nzb מספר שניות בין סריקות עבור קבציסיסמת חשבון רשותיתשם משתמש רשותי של חשבוןאוקטוברכבויתור ישן התגלה, השתמש במצב->תיקון כדי להמיר את התורבסיוםחלופי NZB בכישלון, נסהבסיום תור(באיזה יום של החודש או השבוע (1=יום שני) ספק האינטרנט שלך מאפס את המיכסה? (לא חובה עם שש:דדהשג מאמרים רק עבור ראש התוררק גישה חיצונית דורשת כניסה.PAR2-בצע בתר-עיבוד רק בעבודות שעברו את כל בדיקות המרוחק (מארח:פתחה) Growl השתמש רק עבור שרת.השתמש רק בשרת זה עבור מדורים אלופתח כתובת של מידעפתח חלון מסוף והקלד את הקו (דוגמה):פתח תיקיית השלמהרשותימשלים רשותי NZBסיסמת אימות רשותיתשם משתמש רשותי של אימותשרת Growl סיסמה רשותית עבורציין באופן רשותי שם קובץאפשרויות!או גרור ושחרר קבצים בחלוןסידורשם מקורי של קובץשם עבודה מקוריעבודות יתומותאחרהודעות אחרותבעיה אחרתאין שימורמושההמפיץ %s דקות!בעוד שבדיקה זריזה הצליחה ,%s-נכשל ב Par וידואמשתניםמספר חלקיסיסמהקובץ סיסמהסיסמאות מוסוות ב-******, אנא הכנס מחדשמוגן בסיסמהנתיבדפוסמפתח דפוסהשהההשהה הכלהשהה הורדה במהלך בתר-עיבודהשהה למשךהשהה למשך שעההשהה למשך 15 דקותהשהה למשך 3 שעותהשהה למשך 30 דקותהשהה למשך 5 דקותהשהה למשך 6 שעות?לכמה דקות להשהות...השהה למשךהשהה עבודות עם עדיפות גבוהההשהה עבודות עם מדורהשהה עבודות עם עדיפות נמוכההשהה עבודות עם עדיפות רגילההשהה בתר-עיבודמושהה.משהה הורדה בתחילת בתר-עיבוד וממשיך בסיום"%s" NZB משהה שכפולאחוז של מהירות קוהרשאות עבור הורדות שלמותאישי API מפתח(דרוש) Prowl אישי עבור API מפתחהערות אישיותעבור גישה חיצונית IPv6 אנא היה מודע ששם המארח 0.0.0.0 יצטרך כתובת.העיקרי שלך usenet אנא הכנס את הפרטים של ספקפתחה.צריך להאזין אליה SABnzbd-פתחה ש%s (%s) בתר-עיבוד נכשל עבורבתר-עיבודבצע בתר-עיבוד רק על עבודות שוודאובתר-עיבודבתר-עיבוד התחיל(%s) בתר-עיבוד בוטל.רשומות יושהו עד שהן לפחות בגיל זה. קביעת עדיפות עבודה אל אילוץ תדלג על העיכובתסריט קדם-תור סומן כנכשלתסריט משתמש של קדם-תורקדם-קביעותוהקלד את הקו (דוגמה): R+לחץ על מקש התחלהקודםמנע איזון-עומסהקודםעדיפותשיתוף סביר של חשבוןבעיה עםתוצאה מעובדתמעבד!התכנית לא התחילההתקדמותעיכוב רביהProwlציבורית IPv4 כתובתטהרשהושלמו NZB טהרנכשלים NZB טהרנכשלים ומחק קבצים NZB טהרטהר היסטוריהNZB טהרומחק קבצים NZB טהרבדף הנוכחי NZB טהרטהר תור?לטהר את ההיסטוריה?לטהר את התורPushbulletPushoverגרסת פייתון(+x) אין ערכת הרשאות ביצוע "%s" לתסריט פייתוןתורהוסף לתור 10 פריטים ראשוניםתור הסתייםמגבלת פריטי תורתיקון תור...בדוק זריזבדיקה זריזהצאמיכסהמיכסה שנותרהתקופת מיכסהמיכסה נוצלה, משהה הורדהתנכשלו בוידוא RAR קבציקבצי RAR וודאו בהצלחהRSSRSS מרווח בדיקתהייתה ריקה %s RSS הזנת%s הריץ אתטווח.אפשרויות הנמצאות בשימוש לעיתים רחוקות. עבור משמעותן והסברן, לחץ על כפתור העזרה ולך אל דף הוויקי
.אל תשנה אותן ללא בדיקת הוויקי תחילה, מאחר שלכמה מהן יש תופעות לוואי רציניות
.ערכי ברירת המחדל הם בין הסוגרייםקרא את כל ההזנות כעתקרא הזנהRSS קרא הזנותRSS קרא את כל הזנות!קרא את עזרת וויקי על זהרענןקצב רענוןקצב רענוןסרבתיקיות קרובות משפחה מבוססות עלנותרזכור אותיNZB הסרומחק קבצים NZB הסרהסר שרתהסר את כל הקבצים שנבחרוהסר עבודות נשלמותהסר עבודות נכשלותנכשלה %s הסרתמסיר עבודהמסיר עבודותשנה שםתיקון(קצר %s) תיקון נכשל, אין מספיק גושי תיקוןמתקן%s ,תיקון נכשלמתקן...חזור על בחינההחלף רווחים בשמות תיקיותהחלף נקודות בשמות תיקיות.החלף נקודות ברווחים בשמות תיקיות.החלף רווחים בקווים תחתונים בשמות תיקיותדווחדורשProwl דורש חשבוןPushbullet דורש חשבוןPushover דורש חשבוןRequiresCatאפסאפס מיכסה כעתיום איפוסהפעל מחדשSABnzbd הפעל מחדש אתהפעל מחדש ללא כניסהמפעיל מחדש את SABnzbd...שחזר ברירות מחדלתוצאההמשךהמשך עבודות עם עדיפות גבוהההמשך עבודות עם מדורהמשך עבודות עם עדיפות נמוכההמשך עבודות עם עדיפות רגילההמשך בתר-עיבודממשיךזמן שימורנסה שובנסה שוב הכלנסה שוב הכלנסה שוב כל הנכשליםנסה שוב את כל העבודות הנכשלותלנסות שוב את כל העבודות הנכשלות בהיסטוריה?לנסות שוב את העבודות הנכשלות?מריץ תסריטמריץ תסריט...%s מריץ תסריט משתמשS01E05 תיקיית פרקS01E05 תיקיית עונהמושבת: לא נמצאה גרסה נכונה! (נמצאה %s מצפה אל %s) SABYenc%s - https://sabnzbd.org/sabyenc לא נמצא! מצפה אל ...SABYenc פירקןהתחיל SABnzbd %sSABnzbd מארחSABnzbd סיסמתSABnzbd פתחתSABnzbd אשף התחלה זריזה שלSABnzbd שם משתמשSABnzbd גרסתSABnzbd שרת רשת:גילה שגיאה חמורה SABnzbdהסתיים SABnzbd כיבוי.של קבצים וספריות בהורדות Unicode צפה לבעיות עם שמות .UTF-8 היא אמורה להיות ,%s הותחל עם הצפנת SABnzbd.ירוץ כעת ברקע SABnzbdSMTP שרתנכשלה, ראה יומן SQL פקודתSSLSSL צפנישבתשמורשמור שינוייםנשמרשמירת %s נכשלהשומר..סרוק תיקייה מושגחת%s תזמן עבור שרת בלתי-קייםתזמוןתסריטקוד יציאת תסריט הוא %s"%s" תסריט החזיר קוד יציאה %s ופלטתסריטיםתיקיית תסריטיםחיפושמספר עונה.יוצפנו, אולם, מתן תוקף לזהות שרת ע"י שימוש באישוריו הוא בלתי אפשרי HTTPS אל שרתי חדשות ואתרי SABnzbd-מ SSL חיבורים מאובטחים .מקומיים עדכניים דרושים CA ומעלה ואישורי OpenSSL 1.0.2 ,פייתון 2.7.9 ומעלהחיבור מאובטח לשרתאבטחה.בחר שפת ממשק רשת.SSL בחר רק אם הספק שלך מתיר חיבוריבחירהשלחשלח קבוצהRSS התראות שליחתשלח חזרה לתור.מוסיפה עבודות לתור RSS שלח דוא"ל כאשר הזנת.מושהה SABnzbd-שלח דוא"ל כשהדיסק מלא ו.פקודת שלח קבוצה לפני בקשת מאמריםGrowl שלח התראות אלשלח התראות אל מרכז ההתראותNotifyOSD שלח התראות אללתור %s שלח אתהפרד כתובות רבות ע"י פסיקספטמברמיון סדרותשרתדורש שם משתמש/סיסמה %s השרתבלתי מהימן HTTPS משתמש באישור %s השרת[%s] משתמש באישור בלתי מהימן %s השרתייתקל בהתעלמות למשך %s דקות %s השרתפרטי שרתכתובת שרת.אינה תקפה "%s:%s" כתובת השרתכתובת שרת דרושההשרת לא היה יכול להשלים בקשהתיאור שרתאיזון-עומס של שרתשם השרת אינו פותרסיסמת שרת.שרת יצא במהלך רצף כניסות.השרת דורש שם משתמש וסיסמה%s על %s שגיאה צדדית של שרת (קוד שרת %s); לא היה ניתן להשיג אתשרתים.קבע דפוס הרשאות עבור קבצים ותיקיות שלמים
בסימון אוקטלי. לדוגמה: 755 או 777.קבע את השרת של ספק האינטרנט שלך עבור דוא"ל יוצא!ההתקנה שלמה כעת?האם ההורדה תמשיך לאחר שהמיכסה אופסההראה הכלהראה אפשרויות עריכההראה נכשליםהראה יומן אירועיםהראה שםהראה שם תיקייההראה חיבורים פעיליםהראה פרטיםהראה ממשקהראה.שםהראה_שםמראה %s עד %s מתוך %s תוצאותמראה תוצאה אחתכבהכבה מחשבSABnzbd כבה אתמכבה...נתפס, שומר ויוצא %s אותגודל"%s" מספר קבצים נכשלו בוידוא מול.חלופי כאשר הורדה נכשלת NZB מספר שרתים מספקים.סליחה, לא יכולנו לפרש את זה. נסה שובמייןמיין מחרוזתמיין לפי גילמיין לפי גיל (החדש ביותר→הישן ביותר)מיין לפי גיל (הישן ביותר→החדש ביותר)מיין לפי גיל הישן ביותר→החדש ביותרמיין לפי גיל החדש ביותר→הישן ביותרמיין לפי שם (א→ת)מיין לפי שם (ת→א)מיין לפי שם א→תמיין לפי שם ת→אמיין לפי גודל (הגדול ביותר→הקטן ביותר)מיין לפי גודל (הקטן ביותר→הגדול ביותר)מיין לפי גודל הגדול ביותר→הקטן ביותרמיין לפי גודל הקטן ביותר→הגדול ביותרמיוןמקורזבלמיוחדמהירותמגבלת מהירות.מרובה-ליבות, הוא זמין עבור פלטפורמות רבות Par2 האץ תיקונים ע"י התקנתמגבלת מהירותהיכון מחשבהתחל אשףמתחיל תיקוןאתחול / כיבוימצבאפשרויות מצב וממשקעצירהעוצר...קפדנינושאהגשהוגש. תודה!יום ראשון!תמוך במיזם, תרוםהורדה חשודה במורידןמתגיםעומס מערכתתיקיות מערכת(Pystone) ביצועי מערכתTEXTגדול מדיפריסה בלשוניות
(תור והיסטוריה נפרדים)הצמד תג לעבודהמטלהתיקייה זמניתתיקיית הורדות זמניותבחן דוא"לבחן התראהבחן שרת...בוחן פרטי שרתויעשה בניה מחדש מלאה של SABnzbd כפתור התיקון יפעיל מחדש את
.תוכן התור, תוך שימור קבצים שהורדו כבר. זה ישנה את סדר התוראוטומטי usenet כלי הורדות.תיבת הסימון ליד שם ההזנה צריכה להיות מסומנת כדי שההזנה תהיה מאופשרת ותסומן באופן אוטומטי עבור פריטים חדשים
."אלא אם תלחץ "אלץ הורדה RSS-כאשר הזנה מתווספת, היא תאסוף רק פריטים חדשים ולא שום דבר שנמצא כבר בהזנת ה.שם המארח לא נקבעמספר החיבורים המותרים ע"י הספק שלךהשרת לא הגיב כראוי לברכת השלום.אין חיבורים שנקבעו. אנא קבע לפחות חיבור אחד.ישנן עבודות יתומות בתיקיית ההורדות
.אתה יכול לבחור למחוק אותן (כולל קבצים) או לשלוח אותן חזרה לתור.מפתח זה מספק זהות למדדן. בדוק את המתאר שלך באתר של המדדן.SABnzbd אל NZB מפתח זה יתיר לתכניות צד שלישי להוסיף קבצי.SABnzbd מפתח זה יתן לתכניות צד שלישי גישה מלאה אלהחודש הזה.בעת הצורך par2 זה מונע הרצות תיקון מרובות ע"י הורדת כל קבציבפתחה זו SSL שרת זה אינו מתירהשבוע הזהזה ימנע רענון תוכן כשסמן העכבר שלך מרחף מעל התור.SABnzbd זה יפעיל מחדש את
השתמש בזה כשאתה חושב שלתכנית יש בעית יציבות.
הורדה תושהה לפני ההפעלה מחדש ותומשך לאחר מכן..זה ישלח דוא"ל בדיקה לחשבונךיום חמישיאזל הזמן.או להתחבר על פתחה שונה SSL אזל הזמן: נסה לאפשרזמן שנותרפסק זמןכותרמילות מפתח של כותרת%s :אל %s :מן תאריך: %s מדווח על דיסק מלא SABnzbd :נושא ,היי .הפסיק להוריד, מאחר שהדיסק כמעט מלא .באופן ידני SABnzbd אנא פנה מקום והמשך את היוםNZB עורר הוספתשטח דיסק קטן מדי, מאלץ השהיה%s יותר מדי חיבורים לשרתיותר מדי חיבורים, אנא השהה הורדה או נסה שוב מאוחר יותרראשתפריט עליוןסה''כפתור בעיותעיצוב חדש רענן המיועל עבור שולחן עבודה והתקנים ניידים. לך אל תצורה -> כללי כדי לשנות את עורך !Glitter נסה את העור החדש שלנו(!נסה לחזות השלמה מוצלחת לפני הורדה ממשית (איטי יותר"%s" עם הסיסמה 7zip מנסהRAR מנסה וידוא מבוססSFV מנסה וידוא%s-מ NZB מנסה למשוך%s מנסה לקבוע מצב של שרת בלתי-קיים"%s" מנסה לחלץ עם הסיסמהיום שלישיכוונוןסוגחאינו מותר כאן "%s" UNC נתיבבלתי רצוי%s ;משיכת כתובת נכשלהתופס כתובות קרס[%s] נתמכת yEnc התגלה, רק הצפנת UUencode.כבר רץ SABnzbd איזשהי תוכנה אחרת משתמשת בפתחה או %s לא היה ניתן לקשר את פתחה %s עלגישה בלתי מורשתבטל חסימה!שרת בלתי מוגדר%s שגיאה בלתי ידועה בעת פענוח.או להתחבר על פתחה שונה SSL בלתי ידוע: נסה להשבית SSL פרוטוקולפעולה בלתי ידועה: %sכישלון בלתי ידוע של אימות בשרת דוא"לפרוק.בתוך ארכיונים (rar, zip, 7z) פרוק ארכיונים[%s] פריקת קינון ארוכה מדיפורקו %s קבצים/תיקיות תוך %sפורק%s ,פריקה נכשלהפריקה נכשלה ,CRC שגיאתפריקה נכשלה, ארכיון דורש סיסמה(FAT?) פריקה נכשלה, קובץ גדול מדי עבור מערכת קבציםפריקה נכשלה, נתיב ארוך מדיפריקה נכשלה, ראה יומן אירועים%s פריקה נכשלה, לא היה ניתן למצוא את?פריקה נכשלה, שגיאת כתיבה או דיסק מלא%s-ניסיון כניסה בלתי מוצלחת מבלתי שמיש NZB קובץבלתי שמיש RAR קובץ%s rar סיומת בלתי רצויה בקובץסיומות בלתי רצויותלמעלהעדכון זמין!העלהNZB העלה.nzb .rar .zip .gz, .bz2 :העלהמעלהזמן פעולההשתמש בקביעות ממשק עולמיותהשתמש בתגים ממדדן.השתמש בשמות זמניים במהלך בתר-עיבוד. השבת כאשר המערכת שלך אינה מתמודדת עם זה כראוי.נכנס לתור NZB-בשימוש לפני שמטמון בשימושאחת IPv4/IPv6 שימושי אם לשרת חדשות יש יותר מכתובתתיקיות משתמשמפתח משתמשמפתח משתמש (דרוש)משתמש התחברמשתמש התחבר לממשק הרשתתסריט משתמש יכול לסמן בדגל עבודה כנכשלהשם משתמשערכים.וידוא ותיקון לא יהיו אפשרייםSFV-וודא בהצלחה ע"י שימוש ב.HTTPS-ע"י שימוש ב RSS וודא אישורים בעת התחברות אל מדדנים ומקורותמוודאמוודא תיקון...מוודאגרסהנמוכה מאודוידאומידרג וידאוהצג יומן תסריטיםנגיף/דואר זבלהמתן %s שניותאזהרה:(מוצפן (במקרה שסופקה, כל הסיסמאות נוסו RAR בגלל קובץ "%s" אזהרה: ביטל את העבודה(%s) בגלל מידרג "%s" אזהרה: ביטל את העבודה%s קובץ בלתי רצוי הוא .RAR סיומת בלתי רצויה בקובץ "%s"-אזהרה: ב (מוצפן (במקרה שסופקה, כל הסיסמאות נוסו RAR בגלל קובץ "%s" אזהרה: השהה את העבודה(%s) בגלל מידרג "%s" אזהרה: השהה את העבודהממתיןאזהרה.מספרית IP הוא דו-משמעי, השתמש בכתובת LOCALHOST :אזהרהאזהרותתיקייה מושגחתמהירות סריקה של תיקייה מושגחתממשק רשתיום רביעי.חדש SABnzbd בדוק פעם בשבוע אחר שחרורמתיכאשר במהלך הורדה מתבהר שיותר מדי נתונים חסרים, בטל את העבודה.בעת מיון, השתמש בתגים ממדדן עבור כותרת, עונה, פרק וכדומה .NZB-אחרת כל מתן השמות נגזר משם ה.כאשר תסריט המשתמש מחזיר קוד יציאה בלתי-אפסי, העבודה תסומן בדגל כנכשלה.מופעל מחדש, השיח יפוג SABnzbd שלך משתנה או IP-כאשר כתובת הלהשתמש, לדוגמה 50 SABnzbd איזה אחוז ממהירות הקו צריך?איזה תסריט עלינו לבצע עבור התראות?מי עלינו לומר ששלח את הדוא"לוויקיWindows התראותמהירות כתיבהXשנהתיקיות שנה-חודש.אתה יכול לקבוע זכויות גישה עבור מערכות מחוץ לרשת המקומית שלך. דורש שרשימה של טווחי רשת מקומית תהיה מוגדרת!יתפקד Plush-כדי ש JavaScript אתה חייב לאפשראתה חייב לקבוע רוחב פס מרבי לפני שאתה קובע מגבלת רוחב פס.שלך היא %s אנו ממליצים על גרסה %s או גבוהה יותר UNRAR גרסת
.קובץ הסיסמאות שלך מכיל יותר מ-30 סיסמאות, בחינת כל הסיסמאות האלו תיקח זמן רב. נסה לכתוב ברשימה רק סיסמאות שימושיותהאישי שלך (דרוש) Pushbullet API מפתחשגיאה "%s" בזמן איחוד קבצים [%s]RAR [%s] שגיאה "%s" בזמן פריקת קבצי[%s] איחד %s קבציםpar2 [%s] אין ערכותקיבל אפשרויות שגויות, בדוק את קביעות תצורה->מתגים שלך PAR2 [%s][%s] בדיקה זריזה בסדר%s :נכשל RAR וידוא מבוסס [%s]%s-תוקן ב [%s]כל הקבצים נכונים ,%s-[%s] וודאו בתיקון דרוש ,%s-[%s] וודאו ב!לא נמצא ..._yenc פירקןמאמריםשמערישיות-מותאמתנקהייוםימיםהשבת שרתהוצבע נגדאפשר שרתקובץששעהשעותמילות מפתחנותרדידנידקהדק.דקותלא מותקןמתוךכבויפועלאואו פחותדף!בינארי... לא נמצא par2מוגן בסיסמהשניהשניותראה קובץ יומןזבלtextבלתי ידועבינארי... לא נמצא unrar!בינארי... לא נמצא unzipוידאושבועSABnzbd-2.3.2/locale/nb/LC_MESSAGES/SABnzbd.mo0000644000000000000000000021651013217005256016400 0ustar 00000000000000 ?o?d]@A BCDE*E'EF,FEF ^FFFF FFFGGGGGG1GGH*#HNHgH?H,I0I@IHIRXI[IJJJ#(JLJiJ#J$JJ JJ.J:K'UK'}KKKKKK K K KK LL!L'%LJMLL/LLLL M&M)8M*bM M MMMMMM M/Mh N NN*ODOFOKO%RO#xOOO OOOO PPPPP PP Q-QHQfQ!Q6Q-Q" R/R>R"\R6RR RR.R'S =SGS]SsSS|SS SSTT.T"FT8iTTTTT TT U U U*UDU \U#fUUU UU*UU6VFVXV_V aVkV qV3V V V V VVVVWWW $W/W @WNW(dWW W-WW X#(XLX&SX zX)XXX4XY? YMYgYY YY,Y,Y1Z5MZZZZ ZZZ'Z[5[ M['X[ [ [[ [ [[ [ [[ [[)\8\R\m\\\\ \\$\\ \ \]#]<] L]V]\]n]] ]]] ] ]]]^^<^Z^r^ ^^4^^S^L_d__H_ _ __ _ ``(`.?`)n`&`,`<`&)aPaka'~aaaaa b 1b&hlh/rhgh ii&i"Ei9hiiii$ii i i jj j'j0j Cjdjgjoj j jj'jjj j jk kk ,k9kSkXk`kvk kk kkk;k-lGl LlWl ilvlzl6lGll" m0mLmEOmDm mm~n,nnn%n# o0oDo_o*oo2o%o p$p';pcpjp p q qq% qFqOqTqdq5~q qqHqnr~rrrrrcrHLsos]t)ct tttttt tttt tu$u@uPu0Xuuuuuuuu u u uv vv%v6vTv\vovtvvvvvvv vv w1w"@w cw+nwww w w,wwwxx /x =x/Gxwxxx;x xxyc%y"yAy,y*zFz3]zzzz!z!z" {0{N{%V{|{{ {{{ {{{4{ | |)| 2|*@| k|v|{| || |(| |||| }}3}E} a}n}}}}}M}%~@~#Y~}~%~~R~<SX"w(-0^cz  À΀# 5 V do  ā́܁ $3BG M X eł ʃԃ  '4; Y c oz ҄2 9C X eq)0Ӆ -K gsy ׆ކ4KTc i s}!Ƈ݇+F@HЈ  ):J]}. GSos| #Š   ,4M  3Ƌ3..])yÌԌ - (9bq$Ѝ"&6:]o):3Q Ïԏ   "?R [g x'(>ܐ.J O [/g/-Ǒ-&#&J$q$331#1U ˓ؓ ".6=SZv ” ǔӔ  0"25QAɗ>N= ˘+֘ W d, 6 ?>Ibh"w!A E %.ApŝΝ71EM_Jʞ-ݞ /B_ -6"B#\."Ҡ$/2D K Vw~b$ $:/ jw#"Ǣ-%( N Xemv | 0E/0`h:pä ݤ %R Us=ɥ!). DRTY1lEB+'#S)wJȧ'&;'b ¨ȨʨΨӨ  #', 1?BFILTY s~ ©ݩxWj%@fW'."Vyݱ!% 5@S   '19k}1޳@Ǵʹ \cdȵ޵ %4&O$v 59),'V ~ ط !%'*JR2 *,:(g  Źѹ׹޹8e+s%@BJ%Y#& *  +}6̼#Ӽ!!7Yt$ .ս; @a'r(;þ )*2$]  R #.GL4^+S ' 1>U\ t  % )6Ga7x/ %3 BM\c| 04+Iu ! '& C<N9$%8/R).? +=Zo5: 8 W b%o ,:V mw})6M\`o   %C_{ ;^ iO   #0,5.b-*,6-N|'#'!>!` *. .2;KSk  "($<#a)$" )J,f$2%"$4Y'q%&"$ .3 J$W|  N \,}!)0 >2Fy/,I9v%  $. 5@I"^.  +6 <Jhw )  4).^  3DD"Y|KL6>,-&E$l- 7>^v) m6ETf$y/ #O*jz# #(LZ_Pq _}  =APSlq"2 !4<CJN i s } "  "*0Jdj z ;).#RX _k1}  *"4ICL)g'F?n6-6*a w!$" #- Q[k}P? : EO W+b &   /=O `n ! h}$*F(;o%*1A Yz-  & 9G`ek $ #(L ju~  +IKOi ~    <F OYq M BL e r~)-5P i s} #"6%Y  %44&iHI7 !3L+ $(06FMen& #8X_ dp?:,>Us#,2 < O&]'$;>za0:3nw     ,> FQg) (C5)_gx22//"*R*}))9969p9   $ 5CRez!    )/8@R o{ .d 7.D, q S Ej  1  E B -    <  ]  g s z  Z ` -w $ J # *6P#B[9y  13Dx(P)(= f-p+:H#(5##G`'r "% k0$:  *C"T*w 0(  ) 1<B R ` k w2@3)0:9 t~)'H\EC  '79=5PIF0%H-nL1)F+p# %)+0 6 AKMU\aj|  >D SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Also test releasesAlwaysApplication TokenApplication token (required)Apply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentComplete FolderComplete folder speedCompletedCompleted Download FolderConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDisable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDownloads will not unpacked.DualView1DualView2E.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: File too large for filesystem (%s)ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra queue columnExtracting...FILTEREDFailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send Windows notificationFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.ForceForce DisconnectForce DownloadFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGo to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHelpHibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIndexer id (%s) not found for ratings fileIndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job failedJob finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocation for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLog inLog outLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMeaningMinimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateMondayMonthMoreMore thumbs down than upMovie NameMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelMultiPar binary... NOT found!NZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification Sent!NotificationsNotifyOSDNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Pre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemember meRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...ResultResumeResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABYenc disabled: no correct version found! (Found v%s, expecting v%s)SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyencSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.SABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScriptsSearchSeason NumberSelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...SubjectSubmitSubmitted. Thank you!SundaySuspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUUencode detected, only yEnc encoding is supported [%s]Unauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown SSL protocol: Try disabling SSL or connecting on a different port.Unknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, file too large for filesystem (FAT?)Unpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unsuccessful login attempt from %sUnusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UptimeUse global interface settingsUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User logged inUser logged in to the web interfaceUser script can flag job as failedUsernameValuesVerification and repair will not be possible.Verified successfully using SFV filesVerifyingVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen the user script returns a non-zero exit code, the job will be flagged as failed.Which percentage of the linespeed should SABnzbd use, e.g. 50Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2017-09-03 14:07+0000 Last-Translator: Steffen Bærø Language-Team: Norwegian Bokmal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:31+0000 X-Generator: Launchpad (build 18511) SABnzbd kan ikke finne filene for webgrensesnittet i %s.
Vennligst installer programmet på nytt.

SABnzbd oppdaget instillinger fra en annen SABnzbd-versjon
men kan ikke bruke disse.

Kanskje vil du fullføre nedlastingskøen i det gamle programmet først?

Etter det kan du starte dette programmet med "--clean"-parameteren.
Dette vil slette nedlastingskø og historie!
SABnzbd leste filen "%s". SABnzbd oppdaget at filen sqlite3.dll is mangler.

Enkelte antivirus-programmer fjerner denne filen.
Vennligst sjekk ditt antivirusprogram og forsøk å installer SABnzbd på nytt.

SABnzbd trenger en ledig TCP/IP-port for sin interne webserver.
Port %s på %s ble forsøkt brukt, men er utilgjengelig.
Enten er porten allerede i bruk av et annet program, eller så kjører SABnzbd fra før av.

Start SABnzbd på nytt med et annet portnummer. SABnzbd krever en gyldig adresse for sin interne webserver.
Du har spesifisert en ugyldig adresse.
Korrekte verdier er localhost og 0.0.0.0

Vennligst start SABnzbd på ny med en gyldig adresse. SABnzbd kommer HELT UTEN GARANTI. Dette er fri programvare, og du kan redistribuere det under visse vilkår. Det er lisensier under GNU GENERAL PUBLIC LICENSE Versjon 2 eller senere versjoner. %s -> Ukjent koding%s => mangler på alle servere, fjerner%s artikler hadde ulike duplikater%s artikler var korrupte%s artikler manglet%s artikler ble slettet%s mappe: %s tilgang mislyktes%s filer på %s%s er ikke en korrekt oktal verdi%s er ikke en godkjent e-post-adresse%s mangler Løs adresse 
SABnzbd er avsluttet.
Vent rundt 5 sekunder og klikk deretter på knappen under.

Last på nytt
+ Feilsøking+ Info+Fjern+Reparere+Pakker opp.nzb Reservemappe0 er høyeste prioritet, 100 er laveste prioritet1x05 Episodemappe1x05 Sesongmappe7ZIP set "%s" er ikke komplett, kan ikke pakke ut7za-binærfil... IKKE funnet!OBS: Mapper kommer til å bli opprettet automatiskt når du Lagrer. Du må angi korrekte søkestier til din mapper for å kunne lagre utenfor standardmappene.Data vil ikke bli flyttet. Krever SABnzbd restart!AlderAPI (Ingen konfigurasjon)API-nøkkelAPI-nøkkel QR-kodeAPI-nøkkel er feil, bruk API-nøkkel fra Konfigurasjon->Generelt i ditt tredjepartsprogram:API-nøkkel mangler, skriv inn API-nøkkelen fra Konfigurasjon->Generelt i ditt tredjepartsprogram:API-nøkkel for ProwlAvbrytAvbryt HvisAvbryt jobber som ikke kan fullføresAvbrutt, kan ikke fullføresAvbrutt, kryptering funnetAvbrøt, rangeringsfilter var lik (%s)Avbryt, uønsket forlenging oppdagetAkseptereIngen tilgangHandlingBruk nedlastinghandlinger ifølge filtreringsreglene.Handling når uønsket filtype blir oppdaget i RAR filer.Reaksjon når kryptert RAR fil lastes nedHandling når uønsket filtype oppdagetHendelserLegg-tilLegg til filLegg til NZBLegg til NZB filer Legg til nedlastingsplanLegg til serverLa til NZB-filAdministrativ MappePåvirkede kategorierTidAlleAlle filer vil bli lagt til samme mappeAlle lokale nettverksadresser starter med disse prefix (ofte "192.168.1.")Tillat lastbalanseringTillat lastbalansering med optimalisering for IPv6Også nye utgivelserAlltidProgram-tokenProgram-token (påkrevd)Bruk på ValgteEr du sikker på at du vil omstarte SABnzbd?Er sikker på at du vil slå av SABnzbd?Er du sikker?ArgumentCachestørrelse for artikklerArtikkel-idMinstHøystLydAudio-rangeringGodkjenning mislyktes, kontroller brukernavn og passord.Autentisering mangler, angi brukernavn/passord fra Konfigurasjon->Generelt i ditt tredjepartsprogram:Gjenoppta automatiskAuto-pause når fri plass er nærme grensen.
I bytes, fulgt av K,M,G,T. For eksempel: "800M" eller "8G"Sortere automatisk etter(midt) alder.BTilbakeSikkerhetskopiUkorrekt svar fra Pushbullet (%s): %sUkorrekt svar fra Pushover (%s): %sFeil skjema %s ved %s:%sFeilaktigt utformet yEnc artikkel i %sBåndbreddeBlokker oppfrisking når musen svever overBunnBla gjennomCPU-modellLagrer artikler i minnet for å redusere diskaktivitet.
I bytes, fulgt av K,M,G. For eksempel: "64M" eller "128M"Lagret %s artikler (%s)AvbrytKunne ikke endre rettigheter på %sKan ikke koble til server %s [%s]Kan ikke opprette %s mappe %sKan ikke sikkerhetskopiere fil %sKan ikke opprette mappe %sKan ikke opprette mappe %sKan ikke lage midlertidig fil for %sKan ikke finne e-post-maler i %sKan ikke finne webmal: %s, prøver standardmalKan ikke starte webserveren, ble sannsynlig vis ikke funnetKan ikke nå SABHelper-tjenestenKan ikke lese %sKan ikke lese den overvåkede mappen %sKan ikke sendes, mangler nødvendig dataKan ikke skrive til historikkdatabase, sjekk filrettigheterKan ikke skrive til INI-fil %sKategorierKategoriEndringer som ikke er lagret vil gå tapt.Endringer krever omstart av SABnzbd!Merk alleSjekk før nedlastingSe etter ny utgaveUndersøkerSjekk intervall (i minutter, minst 15). Ikke aktiv når du bruker nedlastingsplan!Velg et skall.Rens listeRensning av %s mislyktesRensNullstill TellereKlikk på gjenta test knappen under for å bestemme.Klikk her for å teste serverinstillingene.SABnzbd kommer ikke til å avsluttes om du lukker vinduet eller fanen i webleseren.Kommaseparert listeKommentarFerdig mappeFerdig mappe-hastighetFerdigFerdig nedlastingsmappeKonfigurasjonKonfig filKonfigurasjonBekreft Sletting av HistorieBekreft Sletting av KøBekreftetKontaker %s@%s feilet, feilmelding=%sTilkobling lyktes!Tilkobling mislykket!TilkoblingerKontainer breddeKunne ikke koble til (%s)Kunne ikke pakke ut %sKunne ikke skrive. Sjekk skrive rettigheter til mappen.Aktuelle nedlastingsplanerTilpasseTDUPLIKATDagligDaglige mapperSkadet historikkdatabase, opprettet ny databaseKontrollpanelDato sorteringDatoformatDag i månedenTitallDekoding av %s mislyktesStandardStandard base filstiFjernFjernTa bort alleSlett FerdigeSlett MislykkedeFjern etter nedlastingSlett alle fullførte nedlastinger fra historie?Slett alle nedlastninger?Slett alt fra køen?Ta bort alle feilmeldinger fra historikken?Fjerning av %s mislyktes!Oppdag duplikatnedlastingerOppdag duplikat episoder i serieEnhetEnheten meldingen skal sendes tilEnhet(er)Enhet(er) som meldingen skal sendes tilDeaktiver kvotebegrensningerDeaktivertDeaktiverte HTTPS på grunn av manglende CERT- og KEY-filer.ForkastKople fra usenet serverne når køen er tom eller pauset.Koble fra når køen er tomFull harddisk varslingDiskfeil under opprettelse av fil %sHarddisken er fullDisken er full! Pauser...Utfør ekstra verifisering basert på SFV filerUgyldig autentisering for nyhetsstrøm %sBlirkvoten resatt hver dag, uke, eller måned?Har du ikke noen usenet leverandør? Vi anbefaler å prøve %s.NedNedlastningNedlasting ferdigMidlertidig nedlastingsmappeNedlasting mislyktesLast ned alle par2 filerNedlastning feilet - Finnes ikke på din(e) server(e)Nedlastingsmappe-hastighetNedlasting kan feile, kun %s av kravet på %s tilgjengeligNedlastetHentet filer på %s med gjenomsnitts hastighet på %sB/sLaster nedNedlastingerNedlastinger vil ikke blir pakket ut.Visning 1Visning 2Eks.F.eks 8 eller 20KRYPTERTFEIL:FEIL: %sFEIL: CRC mislyktes i "%s"FEIL: Filen er for stor for filsystemet (%s)FEIL: sti er for lang (%s)FEIL: kunne ikke finne "%s"FEIL: skrive feil (%s)Tid igjenEndreEndre NZB detaljerEllers Pause HvisE-PostE-Post varsling når nedlasting er ferdigE-post mottakerE-post avsenderSendte E-post!Mappe for E-post malerE-post adresse til mottaker.E-post sendning lykkesNødssituasjonTomTom NZB-fil %sTom RSS post funnet (%s)AktivereAktiver 7zipAktiver datosorteringAktiver filtreringAktiver GrowlHTTPS AktivereAktiver filmsorteringAktiver NotifyOSDAktiver Prowl-varslingerAktiver Pushbullet-varslingerAktiver Pushover-varslingerAktiver SFV-baserte sjekkerAktiverer TV sorteringAktiver UnzipWindows-varslingerAktiverer tilgangen til webgrensesnittet med HTTPS adresse.Aktiver omdøping av mappeAktiveres for mindre minneforbruk. Deaktiver for å forhindre langsom jobb da køen blokkeres.Aktiver kvotebegrensningerAktiver rekursiv utpakkingAktivertVed å avslutte filstien med en asterisk * vil arbeidsmapper ikke bli opprettetURLEpisodenavnEpisodenummerEpisode.NavnEpisode_NavnFeilFeil "%s" under kjøring av file_join på %sFeil "%s" under kjøring av par2_repair på %sFeil "%s" under kjøring av rar_unpack på %sFeil "%s" under kjøring av unzip() på %sFeil %s under kjøring av par2_repair på %sFeil %s: Du må oppgi et gyldig brukernavn og passord.Kunne ikke lage SSL-nøkkel eller sertifikat.Kunne ikke hente TV info (%s)Kunne ikke importere %sLastingsfeil %s, feilaktig fil oppdagetFeil ved fjerning av %sKunne ikke fjerne arbeidsmappe (%s)Kunne ikke endre navn fra "%s" til "%s"Kunne ikke legge til %s, tar bortFeil under avslutting av systemetBara ved feilFeil: Fillengde bør være kortere enn %s.Feil: Køen er ikke tom, kan ikke bytte mappe.Feil: Feil sesjonsnøkkelFeil: Krever sesjonsnøkkelFeil/AdvarselAltEksempelAvslutt SABnzbdendelseEkstern internettilgangEkstra PAR2 parametereEkstra kø-kolonneTrekker ut...FILTRERTMislyktesKunne ikke logge inn på server %sOpprettelse av (%s) mislyktesKunne ikke flytte %s til %sAutentisering mot mailserveren mislyktesKunne ikke stenge databasen, se loggKunne ikke stenge e-post-tilkoblingKunne ikke lage regex for søkestreng: %sKunne ikke koble til mailserverDvalemodus feiletKunne ikke importere %s filer fra %sFeilet å starte %s@%s grunnet: %sKunne ikke starte TLS-tilkoblingKlarte ikke å flytte filerKunne ikke endre navn på lik fil: %s til %sKunne ikke endre navn fra: %s til %sKlarte ikke restarte NZB etter forhåndssjekk (%s)Kunne ikke hente RSS-kilde fra %s: %sKlarte ikke å sende Prowl meldingKlarte ikke å sende Windows meldingKunne ikke sende e-postKlarte ikke å sende pushbullet-meldingKlarte ikke å sende pushover-meldingKunne ikke sette systemet i ventemodusKunne ikke starte webgrensesnittetKunne ikke starte webgrensesnittet: FeilFeil i tempfil.mkstempKritisk feilKritisk feil ved lagring av tilstandKritisk feil i AssemblerRSS-kildeHentHent NZB fra URLHenterHenter %s blokker...Henter ektra blokk...Fil %s er tom, hopper overFilendelseFil som inneholder alle passordene som skal forsøkes på krypterte RAR filer.Filsammenslåing av %s mislyktesFilnavn eller søkesti til HTTPS Sertifikat.Filnavn eller sti til HTTPS-lenkeFilnavn eller søkesti til HTTPS Nøkkel.FilsettFilnavnFilterFiltrere ut sample-filer (ex. video samplinger).FørsteMappe som inneholder brukerdefinerte e-post maler.Mappe som automatiskt søkes igjennom etter .nzb filer.
Skanner også igjennom .zip .rar og .tar.gz arkiver etter .nzb filer.Mappe/SøkestiMapperBrukernavn for e-post som krever autentisering.Passord for e-post som krever autentisering.For servere: sørg for at navn er kompatibel med Windows.TvingTving frakoblingTving nedlastingFormater: .nzb, .rar, .zip, .gz, .bz2ForumLedig (midlertidig)Ledig plassHyppighetFredagFra SxxEyyFull APIFullt webgrensesnittØvrig hjelp kan du finne på vårGBGenereltGenerer Ny NøkkelGå til SABnzbdGå til guidenGrowlHTTP og HTTPS-portene kan ikke være det sammeHTTPS SertifikatHTTPS-lenke sertificaterHTTPS NyckelHTTPS-portHjelpDvalemodus PCSkjul redigeringsalternativerSkjul detaljerSkjul/vis fullførte filerHøyHistorikkHistorikk (10 siste)Historikk-grenseHold shift-tasten for å velge et områdeHjemStartsideAdresseAdressen som SABnzbd skal bruke.Hvor lenge ønsker du å pause? (skriv på engelsk!)Hvor mye can lastes ned denne måneden (K/M/G)INAKTIVUFULLSTENDIGIONice parametereIPv6-adresseIRCLedigOm tom, så vil standardporten bare lytte til HTTPSPrøv et annet nummer hvis du får denne feilmeldingen på nytt.
Ignorer Sample-filerIgnorer alle mapper inne i arkiverIgnorerer duplikatfil "%s"Hvor:I tilfelle "Pause", så trenger du å sette et passord og gjenoppta jobben.Hvis SABnzbd skulle starte på nytt vil denne skjermen forsvinne automatisk!I mappeFor å laste ned fra usenet trenger du tilgang til en leverandør. Din internettleverandør kan gi deg tilgang, men en "proff" leverandør anbefales.Ukompatibel nyhetsstrømFeilaktig kø-fil funnet, kan ikke fortsetteUfullstendig mappeUfullstendig NZB-fil %sUfullstendig sekvens av oppdelte filerFeilaktig RSS-kilde beskrivelse "%s"Feil parameterFeil verdi for %s: %sFeil kodet passord %sFant ikke indekser id (%s) for rangeringsfil.IndekseringFeilaktig NZB fil %s, hopper over (årsak=%s, linje=%s)Ugyldig koding av e-post mal %sUgyldig server-adresse.Ugyldige server-innstillingerUgyldig scenen logging i historien for %sInvertereDet er anbefalt at du lagrer denne siden som et bokmerke for å treffe SABnzbd når det kjøres i bakgrunnen.Jobb mislyktesJobb fullførtSlå sammen filerSlår sammen filerLa nedlastningen i ekstramappe væreSpråkSisteSeneste AdvarslerStarter webleseren ved oppstartStarter standard webleser når SABnzbd starter.HastighetsbegrensningLenkerSkriv alle uønskende filtyper. For eksempel: exe eller exe, comListe over filtyper som skal slettes etter nedlasting.
For eksempel: nfo eller nfo, sfvListe over lokale nettverksområderLasterLasting av %s mislyktesLaster %s feilet med feilmelding %sLokal IPv4-adresseLokasjon for køadmin og historikkdatabase.
Kan bare endres når køen er tom.Plass for lagrede loggfiler fran SABnzbd.
Krever omstart av SABnzbd!Plass for å lagre bearbeidede og ferdige nedlastinger.
Kan overstyres av brukerdefinerte kategorier.Plass for å lagre ikke bearbeidede nedlastinger.
Kan kun endres når køen er tom.Plass der .nzb filer lagres.LoggmappeLogg påLogg avLoggingMistet tilkobling til SABnzbd..LavSmå bokstaverMBGjør Windows-kompatibelLikeMaks. hastighetMaks linje-hastighetMaksimum antall forsøk per serverMaksimum antall forsøkBetyrMinimal fri plass for midlertidig nedlastingsmappeMangler sesjonsnøkkelManglende artiklerModererMandagMånedMerFlere tommeler ned enn oppFilm NavnFilm.NavnFilm_NavnFlytterFlytter...MultioperasjonerMulti-del etikettMultiPar-binærfil... IKKE funnet!NZB-nøkkelNZB er lagt til i køenNavnNavnserver / DNS oppslagFilnavnAldriNy utgave %s tilgjengeligNy utgave er tilgjengeligNesteNice parametereIngen tilgangIngen e-post-mal funnetIngen mappeIngen etterbehandling, på grunn av misslykket verifiseringIngen mottaker oppgitt, e-post ikke sendtIngen resultaterIngen passende autentiseringsmetode ble funnetIngenNormalIngen treffIkke tilgjengeligIkke nok diskplass for å fullføre nedlastingen.UbruktIngenting er valgt!VarselsenterVarsel sendt!VarslerNotifyOSDSekunder mellom skanninger for .nzb filer.VALGFRITT PassordVALGFRITT BrukernavnAvGammel kø oppdaget. Bruk Status -> Reparer for å konvertere køenVed avslutningNår den feiler, prøv alternativ NZB-filNår køen er ferdigPå hvilken dag i måneden eller uken (1=mandag) resetter til nettilbyder kvoten? (Valgfritt med tt:mm)Bara artiklene fra begynnelsen av køenEtterbehandle kun nedlastinger som har passert PAR2 kontrollen.Brukes kun for fjerntliggende Growl tjener (vert:port)Bruk denne serveren kun for disse kategorieneÅpne informasjons-URLÅpne et terminalvindu og skriv inn linjen (eksempel):Åpne fullført mappeValgfrittAlternativ tilleggs NZBKan velge autentiserings passord.Kan velge autentiserings brukernavn.Valgfritt passord for Growl tjenerValgfritt spesifiser filnavnAlternativerEller dra og slipp filer i vinduet!SorteringOriginalfilnavnEtterlatte jobberAndreAndre meldingerAndre problemerDet du prøver å laste ned er eldre enn hva usenet leverandøren din har lagretPausePar verifisering feilet på %s, mens hurtigsjekk var vellykket!ParametereDelnummerPassordPassordfilPassordet er skjult med ******, prøv igjenPassordSnarveiMønsterHjelp til SorteringsstrengStans midlertidigPause AlltPause nedlasting under etterbehandlingPause forPause 1 timePause 15 minutterPause 3 timerPause 30 minutterPause 5 minutterPause 6 timerPause i hvor mange minutter?Pause i...Pause jobber med høy prioritetPause jobber med lav prioritetPause jobber med normal prioritetPause etterbehandlingPausetPauser nedlasting når etterbehandling begynner og gjenopptar nedlasting når etterbehandling er ferdig.Stanser duplikatfil "%s"Prosent av linjehastighetRettigheter for ferdige nedlastingerPersonlig API-nøkkelPersonlig API-nøkkel for Prowl (påkrevd)Persolige notaterHusk at vertsnavnet 0.0.0.0 krever en IPv6-adresse for ekstern tilgangSkriv inn opplysningene om din primære usenet leverandør.PortPorten som SABnzbd skal bruke.Etterbehandling mislyktes for %s (%s)PostprosesseringEtterbehandle kun verifiserte nedlastingerEtterbehandlingEtterbehandling startetEtterbehandling ble avbrutt (%s)Før-kø bruker skriptFor innstillingerTrykk Start+R og skriv inn linjen (eksempel):ForrigeForhindre lastbalanseringForrigePrioritetMistenkt kontodelingProblem medProsesser resultatBearbeidingerProgrammet startet ikke!JobbProwlOffentlig IPv4 adresseSlett og ryddFjern Ferdige NZBerFjern Mislykkede NZBerFjern Mislykkede NZBer & Slett FilerSlett historikkSlett NZB-filerSlett NZB & tilhørende filerSlett køVil du virkelig slette historikken?Vil du virkelig slette køen?PushbulletPushoverPython-versjonKøKø (10 første)Køen er ferdigKø-grenseReparer KøHurtigkontroll...HurtigkontrollererAvslutteKvoteGjenværende kvoteKvoteperiodeKvote oppbrukt, setter nedlasting på pauseRRSSRSS OppdateringsintervallRSS-kilde %s var tomKjørte i %sIntervallSjeldent brukte valg. for å finne forklaring og betydning, klikk på hjelpknappen for å gå til Wiki siden.
Ikke endre på disse uten å sjekke Wiki først, siden noen av dem har alvorlige bieffekter.
Standardverdiene står i parantes.Les alle kilder nåLes kildeLes RSS-kildeLes alle RSS-kanalerLes Wiki Help fer dette!OppdatereOppdateringsfrekvensOppdateringsfrekvensAvviseRelative mapper er basert påGjenstårHusk megFjern NZBFjern NZB & slett filerTa bort serverFjern alle valgte filerFjern ferdige jobberFjerne mislykkede jobberFjerning av %s mislyktesEndre navnReparererMislykket reparasjon, finner ikke nødvendige reparasjonsblokker (%s mangler)ReparererReparasjon mislyktes, %sReparerer...Gjenta testErstatt mellomrom i mappenavnErstatt punktum i mappenavnErstatt punktum med mellomrom i mappenavnErstatt mellomrom med understrek i mappenavn.RapportKreverKrever en Prowl-kontoKrever en Pushbullet-kontoKrever en Pushover-kontoKreverKatNullstillNullstill kvote nåNullstillingsdagStarte på nyttStart SABnzbd på nyttRestart uten å logge innStarter SABnzbd på nytt...ResultatGjenopptaGjenoppta jobber med høy prioritetGjenoppta jobber med lav prioritetGjenoppta jobber med normal prioritetGjenoppta etterbehandlingGjenopptarTidsrom for liggefristPrøv igjenPrøv alle på nyttPrøv alle på nyttPrøv alle mislykkede på nyttPrøv alle mislykkede jobber på nyttPrøv alle mislykkede jobber i historikken på nytt?Prøv alle mislykkede jobber på nytt?Kjører skriptKjører skript...Kjør brukerskript %sS01E05 EpisodemappeS01E05 SesongmappeSABYenc deaktivert: Fant ikke korrekt versjon! (Fant v%s, forventet v%s)SABYenc modul... IKKE funnet! Forventet v%s - https://sabnzbd.org/sabyencSABnzbd %s startetSABnzbd AdresseSABnzbd PassordSABnzbd-portSABnzbd Hurtigstart GuideSABnzbd BrukernavnSABnzbd VersjonSABnzbd WebbserverSABnzbd oppdaget en kritisk feil:SABnzbd er nå avsluttetSABnzbd ble startet med koding %s, dette burde være UTF-8. Forvent problemer med Unicode filer- og katalognavn i nedlastinger.SABnzbd kommer nå å kjøres i bakgrunnen.SMTP-tjenerSQL-kommando mislyktes, se loggSSLLørdagLagreLagre endringerLagretLagring av %s mislyktesLagrer..Sjekk overvåkingsmappeSkjema for ikke eksisterende server %sNedlastingsplanSkriptSkript-avsluttingskode er %sSkriptsSøkSesongnummerVelg språket til Webgrensesnittet.Velges kun om din leverandør tillater SSL-tilkoblinger.UtvalgSendSend gruppeSend RSS varslerSend tilbake til køSend e-post nå en RSS feed legger til en nedlasting til køen.Send e-post når harddisken er full og SABnzbd har pauset.Send gruppekommando før du ber om artikler.Send varsler til GrowlSend varsler til VarselsenterSend varsler til NotifyOSDSendte %s til køenSeriesorteringServerServer %s krever brukernavn/passordServer %s bruker et usikkert HTTP sertifikatServer %s vil bli ignorert i løpet av %s minutterServerinstillingerTjeneradresseServeradressen "%s:%s" er ikke gyldig.Krever server-adresseServerbeskrivelseServerlastbalanseringKunne ikke finne servernavnPassord for tjenerServer avbrøt undet innloggingssekvensServer krever brukernavn og passord.Serverside-feil (serverkode %s); kunne ikke hente %s på %sServereSett rettigheter for ferdige filer og mapper.
Bruk tall. For eksempel: "755" or "777"Still inn din ISP's server for utgående e-post.Installasjonen er nå ferdig!Skal nedlasting starte på nytt etter at kvoten er resatt?Vis alleVis redigeringsalternativerVis MislykkedeLoggShow NavnVis Navn på mappeVis aktive tilkoblingerVis detaljerVis grensesnittShow.NavnShow_NavnViser %s til %s av %s resultatViser et resultatAvsluttSlå av PCAvslutning av SABnzbdStarter avslutning av SABnzbd..Signal %s mottatt, lagrer og avslutter...StørrelseSome files failed to verify against "%s"Noen servere vil gi en alternativ NZB når en nedlasting mislykkes.Beklager, vi kunne ikke finne ut av det. Prøv igjen.SortereSorteringsstrengSortere etter alderSorter på Alder (Yngst%rarr;Eldst)Sorter på Alder (Eldst%rarr;Yngst)Sorter etter alder Ny→EldstSorter etter alder Eldst→NySorter på Navn (A%rarr;Å)Sorter på Navn (Å%rarr;A)Sorter etter navn A→ZSorter etter navn Z→ASorter på Størrelse (Størst→Minst)Sorter på Størrelse (Minst→Størst)Sorter etter størrelse Størst→MinstSorter etter størrelse Minst→StørstSorteringKildeSøppelpostSpesiellHastighetHastighetsgrenseHastighetsgrenseVentemodus PCStart VeiviserStarter reparasjonOppstart/avsluttningStatusStatus og grensesnittalternativerStoppAvslutter...EmvneSendSendt. Takk!SøndagMistenker feil i nedlasterSvitsjerSystemlastSystemmapperSystemytelse (Pystone)TEKSTFOR STOROppgaveMidlertidig MappeMidlertidig nedlastingsmappeTest E-postTest varslingenTestserverTester serverinstillinger...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.Det automatiske usenet nedlastnings verktøyetAvkrysningsboksen ved kildenavnet må aktiveres for at kilden automatiskt skal kontrolleres for nye objekt.
Når en kilde legges til, legges det kun til nye objekt(ikke objekt som allerede finnes). Alle objekter i kilden vises når du klikker på "Tving nedlastning".Du har ikke stilt inn vertsnavn.Antallet tilkoblinger som er tillatt av din leverandørServeren svarte ikke ordentlig til helo hilsenIngen tilkoblinger er aktivert. Du må aktivere minst en tilkobling.Det finnes foreldreløse jobber i nedlastningsmappen.
Du kan velge å slette disse (filene vil også bli slettet) eller sende dem tilbake i nedlastningskøen.Denne nøkkelen vil gi tredjepartsprogrammer lov til å legge til NZBer til SABnzbdDenne nøkkelen vil gi tredjepartsprogrammer full tilgang til SABnzbdDenne månedenDenne serveren tillater ikke SSL på denne portenDenne ukenDette vil hindre oppfrisking av innhold når muspekeren er over køenDette vil starte om SABnzbd.
Brukes når du tror programmet er ustabilt.
Nedlastning vil bli satt på pause før omstarten og gjenoppta etterpå.Dette vil sende en test e-post til din konto.TorsdagTidsavbruddTidsavbrudd: Prøv å aktivere SSL eller bruk en annen port.GjenstårTidsavbruddTittelTittel-nøkkelordTo: %s From: %s Date: %s Subject: SABnzbd rapporterer at disken er full Hei, SABnzbd har stoppet all nedlasting da lagringsdisken nesten er full. Frigjør mer diskplass og gjenoppta nedlasting manuelt. I dagVis/Skjul Legg til NZBFor lite diskplass, nedlasting satt på pauseFor mange tilkoblinger til server %sFor mange tilkoblinger, sett nedlasting på pause eller prøv igjen senereToppToppmenyTotaltFeilsøkingPrøv vår nye skin Glitter! Nytt og friskt design som er optimalisert for stasjonære og mobile enheter. Gå til Konfig -> Generelt for å endre ditt skinPrøve å beregne om ferdigstillelse er mulig før selve nedlastingen (tregere!)Prøver 7zip med password "%s"Prøver SFV-verifiseringForsøker å hente NZB fra %sForsøker å sette status på ikke-eksisterende server %sPrøver unrar med passord "%s"TirsdagJusteringerTypePUNC-sti "%s" er ikke tillatt herUØNSKETURL henting mislyktes; %sURLGRABBER KRASJETUUencode oppdaget, bare yEnc koding er støttet[%s]Uautorisert tilgangFjern blokkeringUdefinert server!Ukjent feil oppstod under dekoding av %sUkjent SSL-protokoll: Prøv å deaktivere SSL eller koble til på en annen port.Ukjent handling: %sUkjent godkjenningsfeil i e-postserverenUtpakkingPakk ut arkiver (rar, zip, 7z) inne i arkiverUtpakking nestet for dypt [%s]Utpakket %s filer/mapper på %sUtpakkerUtpakking mislyktes, %sUtpakking mislyktes, CRC-feilUtpakking mislyktes, arkivet krever passordUtpakking feilet, filen er for stor for filsystemet (FAT?)Utpakking feilet, stien er for langUtpakking mislyktes, se loggUtpakking mislyktes, kunne ikke finne %sUtpakking mislyktes, skrivefeil eller er disken full?Mislykket påloggingsforsøk fra %sFeil, Ubrukelig akrivfilUbrukelig RAR-filUønsket forlenging finnes i rar fil %sUønsket filtyperOppOppdatering tilgjengeligLast OppLast opp NZBLast Opp: .nzb .rar .zip .gz, .bz2OppetidBruk globale grensesnittinnstillingerBruk midlertidige navn under postprosessering. Deaktiver når systemet ditt ikke håndtere dette skikkelig.Brukes før en NZB blir lagt til køBrukt hurtigbufferNyttig hvis en newsserver har mer enn en IPv4/IPv6-adresseBrukermapperBrukernøkkelBrukernøkkel (påkrevd)Bruker påloggetBruker logget inn i webgrensesnittBrukerskript kan flagge jobb som mislykketBrukernavnVerdierVerifikasjon og reparasjon vil ikke være mulig.Verifisering med SFV-filer var vellykketVerifisererVerifserer...VersjonVeldig lavVideoVideo-rangeringSe skriptloggVirus/spamVENT %s sekADVARSEL:ADVARSEL: Avbrøt jobb "%s" grunnet rangering (%s)ADVARSEL: I "%s" uønsket filtype i RAR fil. Uønsket fil er %s ADVARSEL: Pauset jobb "%s" grunnet rangeringen (%s)VenterAdvarselAdvarsel: LOCALHOST er tvetydig, bruk numerisk IP-adresse.AdvarslerOvervåket MappeSkanningsintervall for Overvåkede mapparWebgrensesnittOnsdagSe etter ny utgave av SABnzbd hver uke.NårAvbryt jobben om det blir klart under nedlasting at for mye data manglerNår brukerskriptet returnerer en ikke-null exit kode, vil jobben bli flagget som mislykket.Hvor mange prosent av linjehastigheten skal SABnzbd bruke, feks. 50Hvem skal vi sende e-posten fra?WikiAktiver Windows-varslingerSkrivehastighetXÅrÅr-Måneds mapperDu må aktivere Javaskript for at Plush skal fungere!Du må sette maks båndbredde før du kan sette en båndbreddebegrensningDin Unrar-versjon er %s, vi anbefaler versjon %s eller høyere.
Din personlige Pushbullet API-nøkkel (påkrevd)[%s] Feil "%s" under filsammenslåing[%s] Feil "%s" under utpakking av RAR fil(er)[%s] Slår sammen %s filer[%s] Ingen par2 deler[%s] PAR2 mottok feil kommandoer, undersøk brytere i Konfigurasjon->Brytere[%s] Hurtigkontroll OK[%s] Reparert på %s[%s] Verifiseing tok %s, alle filer er ok[%s] Verifisering tok %s, krever reparasjon_yenc-modul... IKKE funnet!artiklerlydjustert for store og små bokstaversletteddagdøgnDeaktiver servernedstemtAktiver serverfilhtimetimernøkkelordgjenstårmmanueltminuttmin.minutter(ikke installert)avavpåellereller mindresidepar2-binærfil... IKKE funnet!passordbeskyttetsekundsekunderse loggfilsøppeltekstukjentunrar-binærfil... IKKE funnet!unzip-binærfil... IKKE funnet!videoukeSABnzbd-2.3.2/locale/nl/LC_MESSAGES/SABnzbd.mo0000644000000000000000000025663013217005256016421 0ustar 00000000000000x#GoGd HrI lJyKmLWM*nM'MMMM N/N>N^N ~NNN@OHOOOWO_OgO1zOOO*OOAPYP?PQ"Q2Q:QRJQ[QQ RR#R>R[R#xR$RR RR.R: S'GS'oSSSSSS S S SSSTTT' TJHTtTU/UMUcUvU}UU UUU)U*U 'V 5V?VSVfVoVwV }VV/VhV *W6WW*AXlXnXsX%zX#XXX XY Y'Y\.Y YYZ.Z5Z UZvZ ZZZZ! [6,[-c["[[["[6\;\ W\b\Gk\l\< ]]].v]'] ]]]^ ^S!^u^ ^^^^.^"^8_G_\_d_s__ __U_` ` &`4`N` f`#p``` ```*`a6*aaasaza |aa a3a a a a aabb-b@bHb\b`b gbrb bb(bb b-cl l ll l ll(l.l)%m&Om,vm<m&mn"n'5n]nonnn n n&n-oHoeoo ooo o ooopp *p8pAp\pcp~pp%p!pp+q x/x x xx'xxy )y 3y>y]yoby yy yyzz%z;zMz `zz zzz;z>z-/{9]{{ {{ {{{6{|G||"|}}E"}Dh} }}Q~,c~~~%~#~2@R*<2%ԁFAY'p1H9; Ӄ ރ} ny *%Ą%.5H ~HnمHemqc$Hoч]A) ɈԈۈ 28 @J$]0,]qa  # 1 <G NXiz‹Njߋ# 3= V1a" + ,'': b pz/͎; /9Yci"͏#A,V*3Ő!1!S"u% " 1?PW4j  *͒   "(, U_pғ -E`vM}˔##%4ZRi<"@Ppj%#I_-g× ܗ %7=QWl ~ Ҙ  !,5<D əؙ +-Hhl Û֛  9 C OZ tŜ ؜ 2 4> S `l)0Ν(F bnt Ҟ %>Zqz !ʟ$;QFfH  '4O`p.> my  Ƣע# #*,Anv ¤ ˤ4 !+ 0;R3e3.ͥ)Bb!s  -֦,(1Zi$x!ק"-&P:wo)*T3k Ʃ өݩ  " ,"6Yl u 'Ȫ(ͪ>.5d i u//--&=&d$$3լ3 1=1o íRϭ " - 8EUfm Ǯή'D I/S   ӯ߯"Ͱα25APS>k= M+A mWwϴ,t > ͶӶ"!A'imv |EYx.ʸ!(-/NWo7a08JJj-Ⱥ/-J jt-6ӻ" -#G.k"ϼ$/ 6 A blsb$ /:: u#"Ҿ-%3LY  οֿ߿   _"0E^/X:  %CRHwUMi=0!&HM cqsxv1E4Bz+E#q)J1&El&'   ' 1?DFKQZ_ahlq v  "(-jo4sb*{)!ATt W^ d o z&,:<HY@P4= Uah|hNen9~$!*'* R]o*uG6+K R\ n|  L0}2%Xu-,D Wb x :wg9|6M'%# ,GMaV M j)t1$)' G(h$D.1*\'w/U+% Q ^Qh_Id4{*' .:VZ1 (! JAk  $#c@  %! $%J_ s*: * 8BD KUFg   " 4 >H L Vcw0')2%Xt(mu'( 6-!OiAm I1/5&e .8!1=4o,=KW 6 3.6> O Y eqw4! #,3Kb3i ) 3GLc   % /Ih!"~$SQUew".) 26Ci-1F#b$0&4=J  /&E"l ""0;$l9#&*,An!5;*9#d!!' $4&Y0 %" ,5:BV^"~\'-.U/)! !#(L StQ2/!;Q^ %1W] s   `B{/%9 NZwo|  6 ;Hez1  $>4E/z:  <ZA4C"b[A &06 , -F  t    L 0 >O 6   Z 6e ' Y  3 0L }  k  cXg    0$"Cfks- Mm>!#m!O,`h,# 4>G Not  $# # '1:2&>Tf]     !-<Rc{   !* <I g-s4,  &7J \ } 5!C`(r]7.FSuJ/D>X  ):Y"` =* h s ~1 ( ,  4 B  U c v    '  '!*+!V! i!)t! !*!(!"2,"_"^z"6"##6# V#.b# ####2Z$$$9$$$% %%% @%M% _%k% %%%% %%%,&5&S&l&"& &&& && '3'J'S'l'~'''' '' ''%'(%()@(j(n(( ((())))&)*'*8*H*Y* r* ~**"* *&**+.+I+b+|+ +7+ ++ + ++,04,Ae, , ,!,(,&- /-<-D- W-a-j---- --&-.&!.)H.r. . .....'.9 /)G/q/////S/K-0y00 00000 0&0 1!1$1 1$12 2$2-252 =2H2 a2k2"2 222$22333*3#-4 Q4]4>l44 4 444W5K^5%55)5626O6 j6t66/66686.*7Y7 m7#z77(7 778"8!488V8488K879P9Na9 9 9 9 9 9 99 :": 4: ?: J:k: z: :: :-::::I;Ag;; ;;3;3<1;<1m<)<)<'<'=3C=3w=1=1=>>>">+> 4>aB>> >>>>>>? ?,? 3?=?F?Z?a?|??? ????@?!@0@5@D@ \@ j@ w@%@@!NApAnB1B0BKB6ChCL&DJsD DdD*.E YEKcEE!tF FFJFG GGG0GGH(H"EHJhHHHHHHPI(I J#J;J;ZJ"JJ JJJ"J JKK=1KaoKK KK+LJ0L{L/L L@L$ M#/M SM]MsM-MDM)N,N%HN.nNNNN,NO,O2OFO NO#[OOOOOlOC=PPAPPPPQ(Q.AQpQQ0Q*QNQ 2R>RTRcR jRtR zRR R R RvR::SRuSS:KTT TCT T T T U"UD+UpU_xUUVVUVP.W7W(WWWWX XX} X.XSXJ!YlY/$Z,TZ2ZZZMZ8[$P[u[.[+[[ \ \&\:\A\C\G\ M\Y\ m\y\\\\ \\\ \\\\\\\\\ \\\]]#],];]@]F]O]n]]] SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!
If authentication is enabled, you will need to login again.NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAdvancedAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")All usernames, passwords and API-keys are automatically removed from the log and the included copy of your settings.Allow load-balancingAllow load-balancing with optimization for IPv6Allow proper releasesAlso test releasesAlwaysApplication TokenApplication token (required)Apply filtersApply to SelectedAprilAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAugustAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically delete completed jobs from History. Beware that Duplicate Detection and some external tools rely on History information.Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseBypass series duplicate detection if PROPER, REAL or REPACK is detected in the download nameCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryCategory folder cannot be a subfolder of the Temporary Download Folder.Certificate hostname mismatch: the server hostname is not listed in the certificate. This is a server issue.Certificate not valid. This is most probably a server issue.Certificate verificationChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking extra filesChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentCompact layoutComplete FolderComplete folder speedCompletedCompleted Download FolderCompleted Download Folder %s is on FAT file system, limiting maximum file size to 4GBConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCorrupt RAR fileCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecemberDecoder failure: Out of memoryDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDetect identical NZB files (based on items in your History or files in .nzb Backup Folder)Detect identical episodes in series (based on "name/season/episode" of items in your History)DeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDirect UnpackDirect Unpack was automatically enabled.Disable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDo not keep any completed jobsDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDownloads will not unpacked.DualView1DualView2Duplicate NZBE.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: File too large for filesystem (%s)ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmergency expireEmergency retryEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Indexer IntegrationEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable notification scriptEnable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExecutes a custom scriptExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra history columnExtra queue columnExtracting...FILTEREDFail job (move to History)FailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send Windows notificationFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: Failing duplicate NZB "%s"FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFebruaryFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File not on serverFile setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user scripts.Folder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.For unreliable servers, will be ignored longer in case of failuresForceForce DisconnectForce DownloadForcing disconnectFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom Show SxxEyyFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGenerate new self-signed certificate and key. Requires SABnzbd restart!Glitter has some (new) features you might like!Go to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHTTPS certificate verificationHelpHelp us translate SABnzbd in your language!
Add untranslated texts or improved existing translations here:Hibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory RetentionHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How many seconds your notification will continue to be retriedHow much can be downloaded this month (K/M/G)How often (in seconds) the same notification will be sentIDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If the SABnzbd Host or Port is exposed to the internet, your current settings allow full external access to the SABnzbd interface.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIncrease performance by forcing a lower SSL encryption strength.Indexer Categories / GroupsIndexer id (%s) not found for ratings fileIndexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to "Indexer Categories / Groups" to match more categories. Use commas to separate terms. Wildcards in the terms are supported.
More information can be found on the Wiki.Indexers can supply rating information when a job is added and SABnzbd can report to the indexer if a job couldn't be completed.IndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid par2 files or invalid PAR2 parameters, cannot verify or repairInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIssuesIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.JanuaryJob "%s" is probably encrypted due to RAR with same name inside this RARJob "%s" is probably encrypted: "password" in filename "%s"Job Name as FilenameJob failedJob finishedJobsJobs will start unpacking during the downloading to reduce post-processing time. Only works for jobs that do not need repair.Join filesJoiningJulyJuneKeep all jobsKeep completed jobs maximum number of daysKeep loose downloads in extra foldersKeep maximum number of completed jobsLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!Location for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLog inLog outLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMarchMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMayMeaningMinimalMinimal: when SSL is enabled, verify the identity of the server using its certificates. Strict: verify and enforce matching hostname.Minimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateModule subprocessww missing. Expect problems with Unicoded file and directory names in downloads.MondayMonthMoreMore thumbs down than upMovie NameMovie SortingMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelMultiPar binary... NOT found!Multicore Par2NZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNone of the enabled servers have the 'Default' category selected. Jobs in the queue that are not assigned to one of the server's categories will not be downloaded.NormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification ScriptNotification Sent!Notification script "%s" does not existNotificationsNotifyOSDNovemberNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOctoberOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly external access requires loginOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOriginal Job NameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPROPAGATING %s minPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause jobs with categoryPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.Pre-queue script marked job as failedPre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressPropagation delayProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge NZBs on the current pagePurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionPython script "%s" does not have execute (+x) permission setQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRAR files failed to verifyRAR files verified successfullyRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemember meRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRemoving jobRemoving jobsRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...Restore DefaultsResultResumeResume high prioirty jobsResume jobs with categoryResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABYenc disabled: no correct version found! (Found v%s, expecting v%s)SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyencSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.SABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSSL CiphersSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScript returned exit code %s and output "%s"ScriptsScripts FolderSearchSeason NumberSecure (SSL) connections from SABnzbd to newsservers and HTTPS websites will be encrypted, however, validating a server's identity using its certificates is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-date local CA certificates are required.Secure connection to serverSecuritySelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeperate multiple URLs by a commaSeptemberSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s uses an untrusted certificate [%s]Server %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer could not complete requestServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeed up repairs by installing multicore Par2, it is available for many platforms.SpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...StrictSubjectSubmitSubmitted. Thank you!SundaySupport the project, Donate!Suspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETabbed layout
(separate queue and history)Tag jobTaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key provides identity to indexer. Check your profile on the indexer's website.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis prevents multiple repair runs by downloading all par2 files when needed.This server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying RAR-based verificationTrying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUUencode detected, only yEnc encoding is supported [%s]Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running.Unauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown SSL protocol: Try disabling SSL or connecting on a different port.Unknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, file too large for filesystem (FAT?)Unpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unsuccessful login attempt from %sUnusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UploadingUptimeUse global interface settingsUse tags from indexerUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User logged inUser logged in to the web interfaceUser script can flag job as failedUsernameValuesVerification and repair will not be possible.Verified successfully using SFV filesVerify certificates when connecting to indexers and RSS-sources using HTTPS.VerifyingVerifying repairVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen sorting, use tags from indexer for title, season, episode, etc. Otherwise all naming is derived from the NZB name.When the user script returns a non-zero exit code, the job will be flagged as failed.When your IP address changes or SABnzbd is restarted the session will expire.Which percentage of the linespeed should SABnzbd use, e.g. 50Which script should we execute for notification?Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou can set access rights for systems outside your local network. Requires List of local network ranges to be defined.You must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your password file contains more than 30 passwords, testing all these passwords takes a lot of time. Try to only list useful passwords.Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] RAR-based verification failed: %s[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2017-12-08 10:47+0000 Last-Translator: Safihre Language-Team: Dutch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-09 05:32+0000 X-Generator: Launchpad (build 18511) SABnzbd kan de web-interface bestanden niet vinden in %s.
Installeer het programma opnieuw.

SABnzbd heeft opgeslagen data van een andere SABnzbd versie gevonden
maar kan de data van deze andere versie niet opnieuw gebruiken.

Rond zo nodig eerst je werk met de andere versie af.

Herstart daarna deze versie met de optie "--clean".
Dit zal de huidige downloads en geschiedenis wissen!
SABnzbd las het bestand "%s". SABnzbd heeft ontdekt dat het bestand sqlite3.dll ontbreekt.

Sommige slecht ontworpen virusscanners verwijderen dit bestand.
Controleer je virus scaner, probeer SABnzbd opnieuw te installeren en klaag bij je leverancier.

SABnzbd heeft een vrije TCP/IP poort nodig voor de interne webserver.
Poort %s op %s is geprobeerd, maar is niet beschikbaar.
Een ander programma gebruikt de poort al of SABnzbd is al actief.

Start SABnzbd met een ander poort nummer. SABnzbd heeft een geldig host adres voor de interne webserver.
Je hebt een onbruikbaar adres opgegeven.
Veilige waarden zijn localhost en 0.0.0.0

Start SABnzbd met een geldig host adres. SABnzbd wordt aangeboden ZONDER ENIGE VORM VAN GARANTIE. Het is vrije software en je mag het, onder bepaalde voorwaarden, verder verspreiden. De licentie is de GNU GENERAL PUBLIC LICENSE Versie 2 of (naar eigen keuze) een latere versie. %s -> Onbekende codering%s => ontbreekt op alle servers, overslaan%s artikelen hadden afwijkende duplicaten%s artikelen zijn misvormd%s artikelen ontbreken%s artikelen zijn verwijderd%s directory: fout %s bij toegang%s bestanden in %s%s is geen correct octaal getal%s is geen geldig e-mailadres%s ontbreekt Adres opzoeken 
SABnzbd is nu afgesloten.
Wacht ongeveer 5 seconden en klik dan op onderstaande knop.

Verversen
+Debug+Info+Opschonen+Repareren+UitpakkenMap voor het bewaren van NZB-bestanden0 is de hoogste en 100 de laagste prioriteit1x05 Aflevering-map1x05 SeizoensmappenDe 7Zip-set '%s' is incompleet, uitpakken is niet mogelijk7za-programma niet gevonden.
Als authenticatie ingeschakeld is, zal je opnieuw moeten inloggen.Let op: mappen worden vanzelf aangemaakt bij "Opslaan".De bestanden worden niet verplaatst. SABnzbd moet herstart worden!LeeftijdAPI (geen Configuratie)API-sleutelQR-code van de API-sleutelAPI-sleutel incorrect; vul de API-sleutel van 'Configuratie' => 'Algemeen' in bij het externe programma:API-sleutel ontbreekt; vul de API-sleutel van 'Configuratie' => 'Algemeen' in bij het externe programma:API-sleutel voor ProwlAfbrekenAfbreken indienDownload afbreken als deze zeker niet kan worden voltooidAfgebroken, kan niet voltooid wordenAfgebroken, versleuteling ontdektAfgebroken, ratingfilter komt overeen (%s)Afgebroken, ongewenste extensie ontdektAccepterenToegang geweigerdActieVerwerk downloads volgens de filter regelsActie wanneer een ongewenste extensie wordt gevonden in een RAR-bestandActie wanneer versleuteld RAR-bestand wordt gedownloadActie bij ontdekken van ongewenste extensieActiesToevoegenBestand toevoegenNZB toevoegenVoeg NZB-bestanden toe Taak toevoegenVoeg server toeDownload toegevoegdAdministratieve mapGeavanceerdBeïnvloede categorieënLeeftijdallesAlle bestanden gaan in één mapAlle lokale netwerk adressen die beginnen met deze reeks (vaak "192.168.1.")Alle gebruikersnamen, wachtwoorden en API-sleutels worden automatisch verwijderd uit het logbestand en de bijgevoegde kopie van je instellingen.Schakel balancering inSchakel balancering met optimalisatie voor IPv6 inSta verbeterde downloads toeOok test versiesAltijdApplicatie tokenApplicatie token (verplicht)Filters toepassenOp selectie toepassenAprilWeet je zeker dat je SABnzbd wilt herstarten?Weet je zeker dat je SABnzbd wilt afsluiten?Weet je het zeker?ParametersArtikelbuffer grootteArtikelnummerMinimaalMaximaalAudioAudio ratingAugustusInloggen mislukt, controleer gebruikersnaam en wachtwoord.Autenticatie ontbreekt; vul gebruikersnaam en wachtwoord van 'Configuratie' => 'Algemeen' in bij het externe programma:Automatisch doorgaanDownload wordt gepauzeerd als er te weinig ruimte vrij isAutomatisch verwijderen van voltooide downloads. Let er op dat Dubbele Download Detectie en andere externe tools Geschiedenis informatie nodig hebben.Automatisch sorteren op basis van gemiddelde leeftijd.BTerugReserveSlecht antwoord van Pushbullet (%s): %sSlecht antwoord van Pushover (%s): %sFoutieve taak %s om %s:%sSlecht opgemaakt yEnc-artikel in %sBandbreedteGeen verversing bij popupsOnderBladerenSla dubbele download detectie over als er in de naam van de download PROPER, REAL of REPACK bevatCPU-modelBewaar de artikelen in het werkgeheugen (verminderd schijf gebruik).
In bytes, in K,M,G notatie. Bijvoorbeeld: "64M" of "128M"%s artikelen (%s) gebufferedAnnulerenToegangsrechten van %s niet aan te passenVerbinding maken met server %s [%s] niet mogelijkNiet mogelijk %s map %s aan te makenBackupbestand maken voor %s niet mogelijkNiet mogelijk directory %s aan te makenKan bestemmingsmap %s niet makenKan geen tijdelijk bestand maken voor %sGeen e-mailsjablonen te vinden in %sWebsjabloon %s niet te vinden; het standaardsjabloon wordt gebruikt.Kan de web-browser niet starten, geen gevondenGeen verbinding mogelijk met de SABHelper-service%s kan niet gelezen wordenBewaakte map %s kan niet gelezen wordenVersturen kan niet, vereiste gegevens ontbrekenNaar de geschiedenis-database schrijven niet mogelijk, controleer de toegangsrechten.Schrijven naar het INI-bestand %s lukt nietCategorieënCategorieEen Categorie specifieke map mag niet een map in de Tijdelijke download map zijn.Servernaam komt niet overeen met de servernamen in het certificaat. Dit is een server-probleem.Certificaat niet geldig. Dit is hoogstwaarschijnlijk een server-probleem.CertificaatverificatieWijzigingen niet opgeslagen en zullen verloren gaan.Wijzigingen worden pas actief na herstart!Selecteer allesControle vóór downloadenPeriodieke controle voor nieuwe versiesControlerenControleren van extra bestandenMinuten tussen het uitlezen (minimaal 15). Niet actief bij gebruik van de Taakplanner!Kies een bedieningsstijl (herstart nodig).Opschoon lijstOpschonen van %s misluktWissenTellers op nulKlik op de Herhaal Test knop om te metenKlik om de verbinding te testen.Afsluiten van het browservenster zal SABnzbd niet stoppen.Door komma's gescheiden lijstCommentaarCompacte weergaveMap voltooidSnelheid van verwerkte downloads mapVoltooidMap voor verwerkte downloadsDe map voor voltooide downloads %s staat op een FAT systeem, de maximale file omvang is dan maar 4GInstellingenInstellingen bestandInstellingenBevestig verwijderen uit geschiedenisBevestig verwijderen uit wachtrijBevestigdVerbinding %s@%s mislukt, bericht=%sSuccesvol verbonden!Verbinding mislukt!VerbindingenBreedte van kaderBeschadigd RAR-bestandKan verbindingsresultaat niet bepalen (%s)Uitpakken %s niet mogelijkKan niet schrijven. Controleer of de map beschrijfbaar is.Huidige takenAangepastODUBBELdagelijksDagelijkse MappenBeschadigde geschiedenis-database, is vervangen door een lege databaseDashboardDatum sorterenDatumnotatieDag van de maandDecenniumDecemberDecoder fout: onvoldoende geheugenDecoderen van %s misluktStandaardBasis mapWisVerwijderAlles wissenVerwijder geslaagdeVerwijder mislukteVerwijderen na downloadVerwijder alle geslaagde items uit Geschiedenis?Alle gedownloade bestanden verwijderen?Verwijder alle downloads uit de wachtrij?Verwijder alle mislukte items uit de Geschiedenis?Verwijderen van %s mislukt.Detecteer dubbele downloadsDetecteer dubbele afleveringen in seriesDetecteer identieke downloads (op basis van downloads in je Geschiedenis of bestanden in je .nzb backup map).Detecteer identieke afleveringen in series (gebaseerd op "naam/seizoen/aflevering" van downloads in je Geschiedenis).ApparaatApparaat dat de berichten moet ontvangenApparatenApparaat of apparaten die het bericht moeten ontvangenDirect UitpakkenDirect Uitpakken is automatisch ingeschakeld.Schakel quotum beheer uitUitHTTPS is uitgeschakeld vanwege ontbrekende CERT- en KEY-bestandenVerwerpenVerbreek verbindingen wanneer de wachtrij leeg is of er gepauzeerd wordt.Verbreek verbindingen wanneer er niets te doen isStuur een e-mail wanneer de harde schijf vol isSchrijffout bij opslaan van bestand %sSchijf is volSchijf is vol; gedwongen pauzeDoe een extra verificatie m.b.v. SFV-bestandenGeen geldige inlog gegevens beschikbaar voor RSS-feed %sBehoud geen enkele downloadWordt het quotum elke dag, week of maand gereset?Heb je nog geen Usenet provider? Wij bevelen %s aan.LagerDownloadDownload voltooidMap voor verwerkte downloadsDownload misluktDownload alle PAR2-bestandenDownload mislukt - Niet meer op je server(s)Snelheid van download mapDownload mislukt waarschijnlijk, slechts %s van de benodigde %s beschikbaarGedownloadGedownload in %s met een gemiddelde snelheid van %sB/sDownloadenDownloadsHet zal niet mogelijk zijn downloads uit te pakken.Dubbel1Dubbel2Dubbele downloadVoorbeeldBv. 8 of 20VERSLEUTELDFOUT:FOUT: %sFOUT: onjuiste CRC in "%s"FOUT: bestand te groot voor het bestandssysteem (%s)FOUT: bestandspad is te lang (%s)FOUT: "%s" niet te vindenFOUT: schrijffout (%s)Klaar omBewerkBewerk download detailsAnders pauzeren indienE-mailStuur een e-mail na het voltooien van elke downloadOntvangerAfzenderE-mail verzonden!Map met e-mailsjablonenAdres waarnaar de e-mail verstuurd wordt.E-mail verzondenNoodgevalEinde van noodgevalNoodgeval herhalingLeegNZB-bestand %s is leegLege RSS-feed gevonden (%s)Inschakelen7Zip toestaanDatum sorteren aanFiltering aanGrowl meldingen activerenActiveer HTTPSSta integratie met index websites toeFilm sorteren aanNotifyOSD activerenProwl berichten activerenPushbullet meldingen activerenPushover meldingen activerenVoer SFV-gebaseerde controles uitSerie sorteren aanUnzip toestaanWindows meldingen activerenWebinterface beschikbaar via HTTPSGebruik tijdelijke mapnamenAanzetten zal leiden tot minder geheugen gebruik.
Uitzetten om te voorkomen dat langzame downloads de wachtrij blokkeren.Notificatie script activerenSchakel quotum beheer inRecursief uitpakken toestaanActiefAls het pad eindigt met een ster *, dan worden geen aparte download mappen gemaakt.URLAflevering NaamAflevering NummerAflevering.NaamAflevering_NaamFoutFout %s bij 'file_join' op %sFout '%s' bij reparatie van set %sFout "%s" bij uitvoeren van 'rar_unpack' op %sFout '%s' bij uitvoeren van unzip() op %sFout %s bij uitvoeren van par2-reparatie op set %sFout %s: Je moet een geldige gebruikersnaam en wachtwoord invullen.Fout bij aanmaken SSL-sleutel en -certificaatFout bij ophalen TV info (%s)Fout bij importeren van %sFout bij inladen van %s, corrupt bestand gevondenFout bij verwijderen van %sFout bij verwijderen van werkmap %sFout bij hernoemen van "%s" tot "%s"Fout bij toevoegen van %s, wordt weer verwijderdFout bij het afsluiten van het systeemAlleen bij foutenFout: het opgegeven pad mag niet langer zijn dan %s.Fout: Wachtrij is niet leeg, andere map kiezen niet mogelijk.Fout: Sessiesleutel niet geldigFout: Sessie sleutel nodigFouten/WaarschuwingenAllesVoorbeeldVoer een zelfgemaakt script uitStop SABnzbdExtensieExterne toegangExtra PAR2 parametersExtra kolom aan geschiedenis toevoegenExtra kolom aan wachtrij toevoegenUitpakken...GEFILTERDKeur download afMisluktAanmelden bij server %s misluktAanmaken (%s) misluktVerplaatsen van %s naar %s misluktAanmelden bij e-mailserver misluktHet lukt niet om de database te sluiten, zie logBeëindigen e-mailverbinding misluktHet compileren van 'regex' voor de zoekterm lukt niet: %sVerbinding met e-mailserver misluktKan systeem niet in slaapstand krijgenImporteren van %s bestanden van %s misluktInitialisatie van %s@%s mislukt, vanwege: %sTLS-verbinding misluktVerplaatsen van bestanden misluktHernoemen van gelijkaardig bestand %s naar %s misluktHernoemen van %s tot %s misluktDownload kon niet herstart worden na de voor-controle (%s).Kan RSS-feed "%s" niet lezen vanwege: "%s"Verzenden van Prowl-bericht misluktVersturen Windows-melding misluktVerzenden van e-mail is misluktPushbullet-bericht sturen misluktPushover-bericht sturen misluktKan het systeem niet in standby krijgenWebinterface kan niet gestart wordenWebinterface kon niet gestart worden: Download '%s' geweigerd omdat het een dubbele isMisluktProbleem met tempfile.mkstempFatale foutOnherstelbare fout bij opslaan statusOnherstelbare fout in de AssemblerFebruariFeedOphalenHaal NZB op via URLOphalen%s herstelblokken downloaden...Extra herstelblokken downloaden...Bestand %s is leeg, overslaanBestandsextensieBestand met alle wachtwoorden die uitgeprobeerd moeten worden op versleutelde RAR-bestanden.Samenvoegen van bestanden %s is misluktNaam of pad naar het HTTPS-Certificaatbestand.Bestandsnaam of padnaam van HTTPS chain-bestandNaam of pad van het HTTPS-sleutelbestand.Bestand bestaat niet op de serverBestandsverzamelingBestandsnaamFilterWat te doen met "sample"-bestanden?EersteMap met scripts van de gebruikerMap met e-mailsjablonen..NZB en .ZIP-bestanden in deze map worden automatisch toegevoegd aan de wachtrij.Map/PadMappenWanneer authenticatie nodig is, de gebruikersnaam.Wanneer authenticatie nodig is, het wachtwoord.Voor opslag op servers: gebruik namen die werken op WindowsVoor onbetrouwbare servers, deze zullen langer worden genegeerd wanneer ze fouten veroorzaken.ForcerenVerbreek verbindingenForceer downloadVerbinding verbrekenFormaten: .nzb, .rar, .zip, .gz, .bz2ForumVrij (tijdelijke map)Vrije ruimteFrequentieVrijdagVanaf Serie SxxEyyVanaf SxxEyyVolledige APIVolledig webinterfaceVoor meer informatie bekijk deGBAlgemeenMaak een nieuwe sleutelMaak een nieuw zelf-ondertekend certificaat en sleutel. SABnzbd moet dan opnieuw gestart worden.Glitter heeft enkele (nieuwe) functies die je mogelijk aanspreken!Ga naar SABnzbdGa naar WizardGrowlHTTP- en HTTPS-poort kunnen niet hetzelfde zijnHTTPS-certificaatHTTPS chain-bestandHTTPS-sleutelbestandHTTPS PoortHTTPS certificaatverificatieHulpHelp ons om SABnzbd in jouw taal te vertalen!
Met nieuwe vertalingen of verbeteringen kun je hier terecht:PC slapenVerberg OptiesVerberg detailsToon/verberg voltooide bestandenHoogGeschiedenisGeschiedenis Laaste 10 ItemsGeschiedenis BewarenItems in geschiedenisHoudt Shift toets ingedrukt om meer te selecterenStartpaginaStartpaginaServerHost adres waar op SABnzbd luistert.Voor hoe lang of tot wanneer wilt u pauzeren? (in het Engels!)Hoeveel seconden moet de notificatie herhaald wordenHoeval mag deze maand worden gedownload (K/M/G)Hoevaak moet de notification herhaald worden (in seconden)RUSTONVOLLEDIG"IONice" parametersIPv6-adresIRCRustIndien leeg, werkt de standaard poort uitsluitend met HTTPS.Als de Host of Poort open is gesteld naar het internet zorgen de huidige instellingen ervoor dat de webinterface volledig beschikbaar is voor externen.Als je dit bericht weer krijgt, probeer dan een ander nummer.
Negeer samplesNegeer mappen binnen archievenDubbele download "%s" overgeslagenInAls je "Pause" kiest, dan dien je een wachtwoord in te stellen en de download vrij te gevenWanneer SABnzbd opnieuw is gestart, gaat dit venster vanzelf weg!In mappenOm te kunnen downloaden van Usenet, heb je een provider nodig. Je Internet bedrijf heeft misschien een server, maar we bevelen een betaalde server aan.Ongeschikte RSS-feedOnbruikbaar wachtrij bestand gevonden, kan niet verderTijdelijke download mapOnvolledig NZB-bestand %sOnvolledige reeks van samenvoegbare bestandenFoutieve RSS-feed definitie "%s"Incorrecte parameterFoute waarde voor %s: %sFoutief gecodeerd wachtwoord %sVerhoog de prestaties door een eenvoudigere SSL versleuteling toe te passen.Indexer Categorieën / GroepenIndexer id (%s) niet gevonden in het bestand met beoordelingenIndexers kunnen een categorie in de NZB plaatsen en SABnzbd zal die proberen toe te passen op onderstaande categorieën. Daarnaast kun je patronen invullen in de kolom "Indexer Categorieën/Groepen". Gebruik komma's om patronen te scheiden. Joker tekens (? en *) zijn toegestaan.
Meer informatie op de Wiki.Indexers kunnen beoordelingen meesturen wanneer een download wordt toegevoegd en SABnzbd kan de indexer informeren wanneer een download niet slaagt.IndexeringFoutief NZB-bestand %s, overslaan (reden=%s, regel=%s)Foutieve codering van e-mailsjabloon %sOngeldige par2 bestanden of ongeldige Par2 parameters, kan niet verifiëren en repareren.Ongeldige servernaamOngeldige servergegevensOngeldig loggen van fase in geschiedenis voor %somkerenProblemenTip: maak een "Bladwijzer" of "Favoriet" voor deze locatie, zodat je SABnzbd gemakkelijk terug kunt vinden.JanuariDownload "%s" is waarschijnlijk versleuteld omdat en een RAR met dezelfde naam in de hoofd RAR zit.Download "%s" is waarschijnlijk versleuteld, omdat "password" in de naam "%s" voor komt.Downloadnaam als BestandsnaamDownload misluktDownload voltooidDownloadsHet uitpakken van downloads wordt al gestart tijdens het downloaden. Dit verkort de tijd die nodig is voor het nabewerken. Dit werkt alleen als de download niet beschadigd is.SamenvoegenSamenvoegenJuliJuniBehoud alle downloadsBehoud voltooide downloads maximaal aantal dagenZet downloads in aparte mappenMaximum aantal voltooide downloadsTaalLaatsteRecentste meldingenStart webbrowser bij opstartenStart de web browser wanneer SABnzbd opstart.Beperk snelheidKoppelingenLijst van alle ongewenste extensies. Voorbeeld: exe or exe, comLijst van extensies die na downloaden verwijderd moeten worden.
Voorbeeld: nfo of nfo, sfvLijst van lokale netwerk bereikenLadenInlezen van %s misluktInlezen %s mislukt (foutmelding %s)Lokaal IPv4-adres"Local Storage" (cookies) is uitgeschakeld in je web browser, niet alle instellingen zullen worden onthouden.Map waar de wachtrij en geschiedenisdatabase worden opgeslagen.
Kan alleen gewijzigd worden als de wachtrij leeg is.Map waarin de log bestanden worden opgeslagen
Vereist een herstart.(kan aangepast worden door de categorieën).Map om onbewerkte downloads op te slaan
Kan alleen gewijzigd worden als de wachtrij leeg is.Map waar reserve kopieën opgeslagen worden.Map voor loggingAanmeldenAfmeldenLoggenVerbinding met SABnzbd verbrokenLaagKleine lettersMBMaak compatibel met WindowsMaartGeselecteerdMax SnelheidMaximale snelheid internetverbindingMaximaal aantal pogingen per serverMaximum aantal pogingenMeiBetekenisMinimaalMinimaal: wanneer SSL geactiveerd is, controleer de identiteit van de server m.b.v. de certificaten. Strikt: controleer en vereis dat het geldige certificaat bij deze servernaam hoort.Minimale vrije ruimte voor tijdelijke download mapSessiesleutel ontbreektOntbrekende artikelenGematigdDe module subprocessww ontbreekt. Je kunt problemen krijgen met Unicode namen van bestanden en mappen.maandagmaandMeerMeer duimen omlaag dan omhoogFilm NaamFilm sorterenFilm.NaamFilm_NaamVerplaatsenVerplaatsen...Meervoudige bewerkingMeervoudig labelMultiPar niet gevonden!Multicore Par2NZB-sleutelDownload aan wachtrij toegevoegdNaamNameserver / DNS opzoekenNaamgevingNooitNieuwe versie %s beschikbaar opNieuwe versie beschikbaarVolgende"Nice" parametersGeen toegangGeen e-mailsjablonen gevondenGeen mappenGeen nabewerking vanwege mislukte verificatieGeen geadresseerden opgegeven, e-mail niet verstuurdGeen resultatenGeen geschikte authenticatiemethode gevondenGeenGeen enkele server heeft de "Standaard" categorie. Downloads in de wachtrij die geen categorie hebben die ook aan een server is gekoppeld, zullen niet worden gedownload.NormaalVerworpenNiet beschikbaarOnvoldoende schijfruimte over!Niet gebruiktNiets geselecteerd!BerichtencentrumNotificatie ScriptMelding verzondenMeldingsscript '%s' bestaat nietMeldingenNotifyOSDNovemberAantal seconden tussen het lezen van de bewaakte map.OPTIONEEL: Account wachtwoordOPTIONEEL: Account gebruikersnaamOktoberUitOude wachtrij gevonden, gebruik Status->Reparatie om te converterenBij lege wachtrijBij mislukking: probeer alternatieve NZBNa afronden wachtrijOp welke dag van de maand of week (1=maandag) wordt het quotum gereset? (Eventueel met hh:mm)Download alleen artikelen van het begin van de wachtrijAlleen voor externe toegang is aanmelden nodigVoer de nabewerking alleen uit op downloads die de PAR2 controles hebben doorlopen.Alleen gebruiken voor een Growl server op een ander systeem (server:poort)Gebruik de server alleen voor deze categorieënOpen Informatie URLOpen een "Terminal" venster en type deze regel in (voorbeeld):Open map met voltooide downloadsOptioneelEventuele extra NZBWachtwoord voor web login.Gebruikersnaam voor web login.Optioneel wachtwoord voor de Growl serverGeef eventueel een andere naamOptiesOf sleep bestanden in dit venster!VolgordeOriginele bestandsnaamOriginele DownloadnaamVerweesde downloadsOverigeAndere berichtenAnder probleemBuiten retentiePAUZEVERSPREIDINGSWACHTTIJD %s minPar-verificatie van %s misgelukt, maar QuickCheck wel gelukt.ParametersVolgnummerWachtwoordWachtwoordenbestandWachtwoord gemaskeerd met ******, voer opnieuw inVersleuteldPadPatroonUitlegPauzeAlles pauzerenOnderbreek downloaden tijdens nabewerkenPauzeerPauzeer 1 uurPauzeer 15 minutenPauzeer 3 uurPauzeer 30 minutenPauzeer 5 minutenPauzeer 6 uurHoeveel minuten pauzeren?Pauzeer...Pauzeer downloads met prioriteit "Hoog"Pauzeer downloads met categoriePauzeer downloads met prioriteit "Laag"Pauzeer downloads met prioriteit "Normaal"Pauzeer nabewerkenGepauzeerdOnderbreek downloaden tijdens nabewerken.Dubbele download "%s" gepauzeerdPercentage van snelheid internetverbindingToegangsrechten voor verwerkte downloadsPersoonlijke API-sleutelPersoonlijke API-sleutel voor Prowl (noodzakelijk)Persoonlijke aantekeningenLet op: als je 0.0.0.0 als hostnaam gebruikt, heb je voor externe toegang een IPv6-adres nodigVul hier de gegevens van je primaire Usenet server in.PoortPoort waar op SABnzbd luistert.Nabewerking van %s mislukt (%s)NabewerkingVerwerk alleen correct geverifieerde downloadsNabewerkingNabewerken gestartNabewerking is afgebroken (%s)Downloads zullen gepauzeerd worden tot ze minimaal deze leeftijd hebben. Instellen van prioriteit Forceren zal de download meteen starten.Wachtrij filter script heeft de download afgekeurdWachtrij-filter scriptStandaardinstellingenGebruik Windowstoets-R en type deze regel in (voorbeeld):VorigeSchakel balancering uitVorigePrioriteitMogelijk delen van accountProbleem metBewerkt resultaatNabewerkingProgramma is niet opgestart!VoortgangVerspreidingswachttijdProwlOpenbaar IPv4-adresOpschonenVerwijder voltooide downloadsVerwijder mislukte downloadsVerwijder mislukte downloads incl. bestandenWis de volledige geschiedenisVerwijder alle downloadsVerwijderen incl. bestandenVerwijder downloads op deze paginaWis wachtrijWis de volledige geschiedenis?Verwijderen uit de wachtrij?PushbulletPushoverPython versiePython-script '%s' heeft geen uitvoerpermissie (+x)WachtrijWachtrij Eerste 10 ItemsWachtrij voltooidItems in wachtrijWachtrij reparatieSnelle Controle...Snelle controleAfsluitenQuotumQuotum overQuotum periodeQuotum verbruikt, download is gestoptRRAR bestanden zijn niet verifieerbaarRAR bestanden zijn succesvol geverifieerdRSSRSS-feed uitlees intervalRSS-feed %s is leeg%s is klaarBereikZelden gebruikte opties. Voor betekenis en uitleg, klik op de Help knop om naar de Wiki te gaan.
Wijzig hier niet zonder eerst de uitleg op de Wiki te lezen. Er kunnen nadelige bijwerkingen optreden.
De standaard instellingen staan tussen haakjes.Alle feeds nu uitlezenUitlezenUitlezen RSS-feedsLees alle RSS-feeds uitLees de Wiki pagina over dit onderwerpVerversVerversingstempoVerverssnelheidTitel Bevat NietMaplocaties gebaseerd opNog te doenMij onthoudenVerwijder downloadVerwijder download incl. bestandenVerwijderVerwijder alle geselecteerde bestandenVerwijder voltooide downloadsVerwijder mislukte downloadsVerwijderen van %s misluktItem aan het verwijderenItems aan het verwijderenNaamReparatieReparatie mislukt, te weinig herstelblokken (%s tekort)ReparerenReparatie mislukt, %sRepareren...Herhaal testVervang spaties in mapnamenVervang punten in mapnamenVervang punten door spaties in namen van mappen.Vervang spaties door onderliggende streepjes in namen van mappen.OverzichtTitel BevatEen Prowl account is noodzakelijkHiervoor is een Pushbullet account nodigHiervoor is een Pushover account nodigCategorie IsHerstelQuotum nu resettenReset dagHerstartStart SABnzbd opnieuwHerstarten zonder loginSABnzbd herstart nu...Beginwaarden terugzettenResultaatDoorgaanHervat downloads met prioriteit "Hoog"Hervat downloads met categorieHervat downloads met prioriteit "Laag"Hervat downloads met prioriteit "Normaal"Hervat nabewerkenHervattenBewaartijdOpnieuwAlles opnieuw proberenAlles opnieuw proberenProbeer alle mislukteProbeer alle mislukte downloads opnieuwAlle mislukte downloads in Geschiedenis opnieuw proberen?Alle mislukte downloads opnieuw proberen?Script uitvoerenScript uitvoeren...Gebruiker script %s looptS01E05 Aflevering-mapS01E05 SeizoensmapSABYenc uitgeschakeld, geen bruikbare versie gevonden! (V%s gevonden, V%s verwacht)SABYenc module... NIET gevonden! Verwacht V%s - https://sabnzbd.org/sabyencSABnzbd %s is gestartHostWachtwoordPoortSABnzbd Snelstart HulpGebruikersnaamSABnzbd versieWebserverSABnzbd heeft een fatale fout ontdekt:SABnzbd is afgeslotenSABnzbd is gestart met de codering %s, dit zou UTF-8 moeten zijn. Je kunt, bij het downloaden, problemen krijgen met Unicode namen van bestanden en mappen.SABnzbd is actief op de achtergrond.SMTP-serverSQL-commando mislukt, zie logbestandSSLSSL-sleutelsZaterdagOpslaanOpslaanOpgeslagenOpslaan van %s lukt nietOpslaan..Bewaakte map uitlezenTaak voor niet bestaande server %sTaakplannerScriptExit code van het script is %sScript gaf code %s en resultaat '%s'ScriptsMap voor scriptsZoekenSeizoen NummerBeveiligde (SSL) verbindingen van SABnzbd naar nieuws servers en naar HTTPS websites worden versleuteld. Maar verificatie van de server identiteit is niet mogelijk. Python 2.7.9 of hoger en OpenSSL 1.0.2 of hoger en actuele lokale CA certificaten zijn nodig.Beveiligde verbinding met de serverBeveiligingKies een taal.Vink dit alleen aan als je provider SSL-verbindingen toestaat.SelectieVerzendenVerzend groepVerstuur een e-mail voor RSSStuur terug naar de wachtrijVerstuur een e-mail wanneer een RSS-feed downloads
aan de wachtrij heeft toevoegd.Stuur een e-mail wanneer SABnzbd gestopt is vanwege een volle harde schijf.Verzend de groepsnaam naar de server.Zend meldingen naar GrowlStuur meldingen naar het BerichtencentrumZend meldingen naar NotifyOSD%s naar de wachtrij gestuurdZet komma's tussen de URLsSeptemberSerie sorterenServerServer %s heeft gebruikersnaam/wachtwoord nodigServer %s gebruikt een onbetrouwbaar HTTPS-certificaatServer %s gebruikt een niet betrouwbaar certificaat [%s]Server %s wordt gedurende %s minuten genegeerdServer instellingenServer adresServeradres "%s:%s" is niet geldig.Serveradres verplichtDe server kon de opdracht niet uitvoerenServernaamBalanceren van server belastingServernaam niet te vindenServer wachtwoordDe server stopte tijdens de loginServer heeft een gebruikersnaam en een wachtwoord nodig.Server fout (code is %s); kon geen %s van %s krijgenServersZet toegangsrechten voor verwerkte bestanden/mappen, alleen octale notatie!Het adres van de e-mailserver van je internet provider.Alles ingesteld!Moet het downloaden automatisch doorgaan bij het ingaan van het nieuwe quotum?Toon AllesToon OptiesToon mislukteDownload logSerie NaamToon Naam mapToon actieve verbindingenToon detailsToon webinterfaceSerie.NaamSerie_NaamToon %s t/m %s van %s resultatenEén resultaatAfsluitenPC afsluitenSABnzbd afsluitenAfsluitenSignaal %s ontvangen, opslaan en afsluiten...OmvangSommige bestanden konden niet geverifieerd worden met "%s"Sommige indexers hebben een alternatieve NZB wanneer een download misluktSorry, het opgegeven kunnen wij niet verwerken. Probeer nogmaals.SorterenSorteertekstSorteer op leeftijdSorteer op Leeftijd (Nieuw→Oud)Sorteer op Leeftijd (Oud→Nieuw)Sorteer op Leeftijd Nieuw→OudSorteer op Leeftijd Oud→NieuwSorteer op Naam (A→Z)Sorteer op Naam (Z→A)Sorteer op Naam A→ZSorteer op Naam Z→ASorteer op Omvang (Groot→Klein)Sorteer op Omvang (Klein→Groot)Sorteer op Omvang Groot→KleinSorteer op Omvang Klein→GrootSorterenBronSpamSpeciaalSnelheidMax. snelheidVersnel reparaties door multi-core par2 te installeren. Beschikbaar voor veel besturingssystemen.Maximum snelheidPC standbyWizard startenReparatie startenOpstarten/AfsluitenStatusStatus en webinterface optiesStopAfsluiten...StriktOnderwerpVerstuurIngediend. Bedankt!ZondagSteun het project, doneer!Vedachte fout in downloaderOptiesSysloadSysteemmappenSysteemprestaties (Pystone)TEKSTTE GROOTWeergave in tabs
(wachtrij en geschiedenis apart weergeven)Label downloadTaakTijdelijke mapTijdelijke download mapE-mail testenTest meldingTest ServerServer instellingen aan het testen...De "Repareren" knop herstart SABnzbd met een complete
reconstructie van de wachtrij, met behoud van al gedownloade bestanden.
Dit beïnvloedt wel de volgorde.De automatische Usenet downloaderOm de RSS-feed automatisch te verwerken, vink het selectievlakje bij de definitie naam aan.
Wanneer een nieuwe feed wordt gedefinieerd, zullen alleen nieuwe items gevonden worden en geen bestaande, behalve wanneer je de op "Forceer download" klikt.Geen hostnaam opgegeven.Het aantal verbindingen dat je provider toestaat.De server reageerde niet op de 'helo'-begroetingEr zijn geen verbindingen opgegeven. Er is minimaal één verbinding nodig.Er staan verweesde downloads in de download map.
Je kunt ze verwijderen (inclusief bestanden) of ze terug naar de wachtrij sturen.Deze sleutel is voor je identificatie door de indexer. Kijk in je profiel op de website van de indexer.Met deze sleutel kan een extern programma NZB-bestanden naar SABnzbd sturen.Met deze sleutel heeft een extern programma volledige toegang tot SABnzbd.Deze MaandDit voorkomt extra reparatie pogingen, doordat alle beschikbare par2 files direct worden gedownload.De server staat geen SSL toe op deze poortDeze WeekDit voorkomt pagina verversing wanneer de muis aanwijzer in de wachtrij is.Deze knop zal SABnzbd herstarten.
Dit kan nuttig zijn wanneer je vermoedt dat het programma niet stabiel is.
Het downloaden zal vóór de herstart gestopt worden en daarna weer doorgaan.Hiermee stuur je een test e-mail.DonderdagTijdslimiet overschredenTijdslimiet overschreden. Probeer met SSL aan of gebruik een andere poort.Te gaanTijdslimietTitelTitel trefwoordenTo: %s From: %s Date: %s Subject: SABnzbd meldt een volle harde schijf Hallo, SABnzbd is gestopt met downloaden omdat de harde schrijf bijna vol is. Maak ruimte vrij en laat SABnzbd weer doorgaan. Vandaag"NZB toevoegen" uitklappenTe weinig schijfruimte, pauze geforceerdTe veel verbindingen met server %sTe veel verbindingen, onderbreek het downloaden of probeer later nog eens.BovenTop menu aan/uitTotaalProbleemoplosserProbeer onze nieuwe skin Glitter. Compleet nieuw design, geoptimaliseerd voor desktops en mobiele apparaten. Ga naar Configuratie => Algemeen om de huidige skin te vervangen.Probeer de succes kans van een download van te voren in te schatten (langzamer!)Uitpakpoging met 7zip en wachtwoord '%s'Probeer RAR-verificatieProbeer SFV-verificatieProbeer NZB op te halen van %sPoging de status van niet-bestaande server %s in te stellenUnrar proberen met wachtwoord "%s"DinsdagAfstellingFilterUUNC-pad '%s' hier niet toegestaan.ONGEWENSTURL ophalen mislukt; %sURLGRABBER FATALE FOUTUUencode gevonden, SABnzbd verwerkt alleen yEnc-codering [%s]Kan niet binden aan poort %s van %s. Andere software gebruikt deze poort of SABnzbd is al actief.Geen toegangsrechtenDeblokkerenOnbekende server.Onbekende fout tijdens het decoderen van %sOnbekend SSL protocol: probeer het zonder SSL of probeer een andere poort.Onbekende actie: %sOnbekende authenticatiefout bij de e-mailserverUitpakkenUitpakken van archieven (rar, zip, 7z) binnen archieven toestaanTeveel niveaus om uit te pakken [%s]%s bestanden/mappen uitgepakt in %sUitpakkenUitpakken mislukt, %sUitpakken mislukt, CRC-foutUitpakken mislukt, archief vereist wachtwoordUitplakken mislukt, bestand te groot voor het bestandssysteem (FAT?)Uitpakken mislukt, bestandspad is te langUitpakken mislukt, zie logUitpakken mislukt, kan %s niet vindenUitpakken mislukt, schrijffout of schijf vol?Mislukte login progin bij %sOnbruikbaar NZB-bestandOnbruikbaar RAR-bestandDe ongewenste extensie zit in RAR-bestand %sOngewenste extensiesHogerUpdate beschikbaar!OphalenNZB uploadenUpload: .nzb, .rar, .zip, .gz, .bz2UploadenTijd in de luchtInstellen voor alle sessiesGebruik indexer informatieGebruik tijdelijke mapnamen tijdens de nabewerking. Zet dit uit wanneer je systeem daar problemen mee heeft.Word uitgevoerd vóór een download aan de wachtrij word toegevoegdGebruikte bufferNuttig wanneer een server meer dan één IPv4 of IPv6-adres heeftGebruikersmappenGebrukers sleutelGebrukers sleutel (verplicht)Gebruiker ingelogdGebruiker heeft ingelogdEen gebruikersscript kan een download afkeurenGebruikersnaamWaardenVerificatie en reparatie zal niet mogelijk zijn.Verificatie m.b.v. SFV-bestanden is geluktControleer certificaten bij beveiligde verbindingen met indexers en RSS-feeds.VerifiërenReparatie controlerenVerificatie...VersieZeer LaagVideoVideo ratingToon Script resultaatVirus/spamWACHT %s secWAARSCHUWING:WAARSCHUWING: Download "%s" is afgebroken vanwege een versleuteld RAR bestand (indien aanwezig, zijn alle wachtwoordenWAARSCHUWING: Download '%s' afgebroken vanwege rating (%s)WAARSCHUWING: Ongewenste extensie ontdekt in "%s". Het ongewenste bestand is "%s" WAARSCHUWING: Download "%s" is gepauzeerd vanwege een versleuteld RAR bestand (indien aanwezig, zijn alle wachtwoorden geprobeerd)WAARSCHUWING: Download '%s' gepauzeerd vanwege rating (%s)WachtWaarschuwingLet op: LOCALHOST is niet eenduidig, gebruik een numeriek IP-adres.MeldingenBewaakte mapBewaakte map verversingsintervalWebinterfaceWoensdagControleer elke week of er een nieuwe SABnzbd versie beschikbaar is.WanneerAls tijdens het downloaden duidelijk wordt dat te veel data ontbreekt, breek dan de download afMaak tijdens het sorteren gebruik van informatie van de indexer zoals titel, seizoen, aflevering, enz. Anders wordt alle informatie uit de naam van de download gehaald.Wanneer het script een exit code anders dan 0 geeft, zal de download worden afgekeurd.Als je IP adres veranderd of SABnzbd opnieuw wordt opgestart, zal de sessie verlopen.Welk percentage van de maximale internet snelheid mag SABnzbd gebruiken? B.v. 50Welk script moet uitgevoerd worden voor de notificatie?Wie zou de email gestuurd moeten hebben?WikiWindows MeldingenSchrijfsnelheidXjaarJaar-Maand MappenJe kunt toegangsrechten instellen voor systemen buiten je lokale netwerk. Hiervoor geef je een lijst van netwerk-bereiken in.JavaScript is nodig voor de werking van Plush!Je moet eerst een maximumbandbreedte instellen voordat je een limiet kunt instellenDe UNRAR-versie is %s, we adviseren versie %s of hoger te gebruiken.
Je wachtwoordenbestand bevat meer dan 30 wachtwoorden, het testen van al deze wachtwoorden kost heel veel tijd. Zorg ervoor dat je alleen maar nuttige wachtwoorden in dit bestand zet.Persoonlijke Pushbullet API-sleutel (verplicht)[%s] Fout "%s" bij samenvoegen van bestanden[%s] Fout "%s" bij het uitpakken van RAR-bestanden[%s] %s bestanden samengevoegd[%s] Geen par2 groepen[%s] PAR2-opties incorrect, controleer Configuratie=>Instellingen schakelaars[%s] Snelle Controle OK[%s] RAR verificatie niet gelukt: %s[%s] Gerepareerd in %s[%s] %s geverifieerd, alle bestanden zijn goed[%s] Geverifieerd in %s, reparatie is nodig_yenc-module niet gevonden.artikelenaudioAanpassen van hoofd- en kleine lettersWissenddagdagenServer uit:negatief beoordeeldServer aan:bestandhuururentrefwoordenovermhandmatigminmin.minniet geinstalleerdvanuitaanofof minderPaginapar2-programma niet gevonden.van wachtwoord voorziensecsecondenzie logbestandspamtekstonbekendunrar-programma niet gevonden.unzip-programma niet gevonden.videoweekSABnzbd-2.3.2/locale/pl/LC_MESSAGES/SABnzbd.mo0000644000000000000000000022354313217005256016420 0ustar 00000000000000|>o>dM?@ ABCD*D'DEE5E NEoE~EE EEEFFFFFF1FFG*G>GWG?GH H0H8HRHH[HH II#IV(TV}V V-VVV#Wh$Mhrh xh h hh hhh hhhh i i i'&iNi`i xi ii ii iiiiii j/j 4j>jCj;bj-jj jj jjj6kG;kk"kkkEkDl _ljlm,mBmTm%km#mmmm*n/n28n%knnn'nnn zo o oo%ooooo5p 9pEpHKpnpq q(q:qZqcmqHqor]r)r ss%sBs FsQsTsls ts~s$sss0sst$t-t4t:t?t Xt ct ntyt tttttttttt u#u(u 8uBu [u1fu"u u+uuu u v,vEvNv`vtv v v/vvvw;w CwMwmwc}w"wAx,Fx*sxx3xxxy!!y!Cy"eyyy%yyy yyz zz.z45z jz uzz z*z zzz zz z(z {*{;{P{b{w{{{ {{{{|(|M/|}||#||%| }R}<n}}}"}}~"~2~J~j~~-~~~~~~ ~  &=FL`f{     %4:O^ o| ހ ",;Nj r  Ƃ 1DK2R  ڃ)0PW`y ń Մ߄ #*1Kd Ʌڅ!)8Jaw  ʆ9.S  ɇχ# !,3JR Y g4 Lj ̈׈335.i)މ %-F(t$ !>"N&q:Ӌoۋ)Ku3Ɍ ی  '4 C M"Wz  '(>.V //Ҏ--0&^&$$я33*1^1ʐѐ֐ސ #4;X ]iqx‘ё   (3 EQk"?@2Y5A”>=ȕ + =WG,Dq z>×̗ԗڗ"!՘A9=F LYE)H`.|˚Ӛښߚ !4HPb-Û/ʛ 7AV-r"Ü#ݜ.0B$Ty ՝ܝb$] : Ȟ՞ޞ"%% K Ubjs y 0E/-]e:m ڠ %RUp=ơ!&+ AOQV1iEB+$#P)tJţ$&8'_ ŤǤˤФ ߤ   $) .<?CFIQV p{ ڥwVQa}7~2ϭ0!3U#o!:Ů& '2N  '10O:F "h4h50 f+-ҳ ?"Yb)*  " -7N ` mx7[&D8k¶Ҷ#!*L `&j  Ʒ;ҷ7Q&$ù!&*6a jv=Q!X.z#'ͻ -.D&sDK߼0+\.t7B۽  ? I+S"ξ cUf"x G+=*(h *  )6V u' .1BK F' ?K\c y/!*%L-r# ; GEW 6BIg' #8/>F2E,'rE    (2 6 CP X0c"!/+5a{5 ) H S`  $9^ t)kV!s X  $3B0I:z1.9DP)$-$'? g%' :="]  , >KTs$-+;=M(%-&/#G7k'E$#6#Z/~-&)+- Yg*' !*Lhg{&. ;9)u L Pth(#!1Ew~$   '2Z]ex0  '-?Rd %0 ):;-v   LL2#MG* r@`y.$#@< }96*4_}h #:.ipw+> Lxe  %E~X@}m#( 7"Ad jwz "0 C)m ) ); U_u { +N*8y 3 E dp F+B[G.v7p].-5c2| #!Ed)j   B U_ov8  5 MZr' &1)X [! ,$Lq#>4-)25\7".)Jt5& $ ' :Hems $  %9P fqz$ &7 I,V&':W pz!  7Pg Y ! 0#>#b,3 ! 7A I Wev$#&; Ydx!/$ 2G$^ #/>!Qs" #  '6+U  ? +7 ?M_4}62.9#h7/+%Q e%s$ %)2*2]D|0ZD  )8So! 8"[Ac_, 2 9 L ?a ? = = .] . , , E E[ C C  )  4 >  C  M Y k           !  4 *> i  x          $2E/ 5<r94b_D6& ]'j D7"\ r} 3$X+  U8.5G7}  %4 Uhq&O5!AW&%-A#8e0:F Qh) $%,R9;1m: .  ;IZ an t  :^;K   7   2  )!7!9>!x!_~!g!IF"-"""""""-#U5#D#(#+#3%$Y$u$c$$%4#%)X%% %% % %%%%% % &&& &(&0& @&K&M&V&]&b&h&z& |& && && &&&& &&''!'!2'T'Z' SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Also test releasesAlwaysApplication TokenApplication token (required)Apply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentComplete FolderComplete folder speedCompletedCompleted Download FolderConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDisable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDualView1DualView2E.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra queue columnExtracting...FILTEREDFailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.ForceForce DisconnectForce DownloadFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGo to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHelpHibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIndexer id (%s) not found for ratings fileIndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job failedJob finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocation for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMeaningMinimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateMondayMonthMoreMore thumbs down than upMovie NameMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelNZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification Sent!NotificationsNotifyOSDNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Pre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...ResultResumeResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScriptsSearchSeason NumberSelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...SubjectSubmitSubmitted. Thank you!SundaySuspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUnauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UptimeUse global interface settingsUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User script can flag job as failedUsernameValuesVerified successfully using SFV filesVerifyingVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen the user script returns a non-zero exit code, the job will be flagged as failed.Which percentage of the linespeed should SABnzbd use, e.g. 50Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2015-12-28 10:22+0000 Last-Translator: Safihre Language-Team: Polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:31+0000 X-Generator: Launchpad (build 18511) SABnzbd nie może znaleźć plików interfejsu WWW w %s.
Proszę ponownie zainstalować SABnzbd.

SABnzbd wykrył dane zapisane w innej wersji SABnzbd
lecz nie może ponownie użyć tych danych.

Zaleca się zakończenie pobierania kolejki w innym programie.

Następnie należy uruchomić SABnzbd z opcją "--clean".
Spowoduje to wymazanie aktualnej kolejki i historii!
SABnzbd czyta plik "%s". SABnzbd wykrył brak pliku sqlite3.dll.

Niektóre źle działające programy antywirusowe usuwają ten plik.
Sprawdź swój program antywirusowy, spróbuj ponownie zainstalować SABnzbd i zgłoś problem dostawcy programu antywirusowego.

SABnzbd wymaga wolnego portu TCP/IP dla wewnętrznego serwera WWW.
Próbowano użyć portu %s na %s, ale nie jest on dostępny.
Inny program używa tego portu lub SABnzbd jest już uruchomiony.

Uruchom ponownie SABnzbd używając innego numeru portu. SABnzbd wymaga prawidłowego adresu hosta dla wewnętrznego serwera WWW.
Podano nieprawidłowy adres.
Bezpieczne wartości to localhost i 0.0.0.0

Uruchom ponownie SABnzbd używając prawidłowego adresu hosta. SABnzbd wydawany jest ABSOLUTNIE BEZ ŻADNEJ GWARANCJI. To jest wolne oprogramowanie i mile widziane jest dalsze rozpowszechnianie go przez ciebie na określonych warunkach. Program jest wydawany na licencji GNU GENERAL PUBLIC LICENSE w wersji 2 lub (według twojego wyboru) którejś z późniejszych wersji. %s -> Nieznane kodowanie%s => nie znaleziono na żadnym serwerze, porzucam%s artykułów posiadało niepasujące duplikaty%s artykułów było uszkodzonychBrakowało %s artykułów%s artykułów zostało usuniętychKatalog %s: błąd dostępu do %s%s plików w %s%s nie jest prawidłową wartością w systemie ósemkowym%s nie jest prawidłowym adresem emailBrakuje %s Rozwiązywanie adresu 
SABnzbd został wyłączony.
Zaczekaj około 5 sekund, a następnie kliknij na przycisk poniżej.

Odśwież
+ Debugowanie+ Informacje+Usuń+Napraw+RozpakujKatalog kopii zapasowych .nzb0 oznacza najwyższy priorytet, 100 - najniższyKatalog odcinka 1x05Katalog sezonu 1x05Zestaw 7zip "%s" jest niekompletny, nie można rozpakowaćProgram 7za... NIE znaleziono!UWAGA: Katalogi zostaną automatycznie utworzone po zapisaniu zmian. Możesz użyć ścieżek absolutnych, aby wskazać lokalizację poza domyślnym katalogiem bazowym.Dane nie zostaną przeniesione. Wymaga restartu SABnzbd!WiekAPI (bez Konfiguracji)Klucz APIKod QR klucza APIKlucz API jest nieprawidłowy, użyj klucza API z sekcji Konfiguracja->Ogólne w zewnętrznym programie:Brak klucza API, należy wprowadzić klucz API z sekcji Konfiguracja->Ogólne do zewnętrznego programu:Klucz API ProwlPrzerwijPrzerwij, jeśliPrzerwij zadania, które nie mogą zostać ukończonePrzerwano, nie można ukończyćPrzerwano, wykryto szyfrowaniePrzerwano, odfiltrowane z powodu oceny (%s)Przerwano, wykryto niepożądane rozszerzenieAkceptujBrak dostępuDziałanieWykonuj działania na zadaniach w oparciu o reguły filtrowaniaDziałanie, które zostanie podjęte po wykryciu w pliku RAR niepożądanego rozszerzeniaDziałanie dla zaszyfrowanych plików RARDziałanie dla niepożądanych rozszerzeńDziałaniaDodajDodaj plikDodaj NZBDodawanie plików NZB Dodaj harmonogramDodaj serwerDodano NZBKatalog administracyjnyDotyczy kategoriiWiekWszystkoWszystkie pliki zostaną rozpakowane do jednego folderuWszystkie lokalne adresy sieciowe zaczynają się od tych prefiksów (często "192.168.1.")Zezwól na równoważenie obciążeniaZezwól na równoważenie obciążenia, preferując IPv6także wydania testoweZawszeToken aplikacjiToken aplikacji (wymagany)Zastosuj do zaznaczonychCzy na pewno zrestartować SABnzbd?Czy na pewno wyłączyć SABnzbd?Czy jesteś pewien?ArgumentyLimit pamięci podręcznej artykułówIdentyfikator artykułuPrzynajmniejNajwyżejAudioOcena audioBłąd połączenia, sprawdź nazwę użytkownika i hasło.Brak danych uwierzytelniających, wprowadź nazwę użytkownika/hasło z sekcji Konfiguracja->Ogólne do zewnętrznego programu:Automatyczne wznawianieAutomatycznie wstrzymaj pobieranie, jeśli pozostanie mniej miejsca niż podano.
W bajtach, opcjonalnie z przyrostkiem K, M, G, T. Przykład: "800M" lub "8G"Automatycznie sortuj pozycje według wieku (średniego)BPowrótZapasowyZła odpowiedź od Pushbullet (%s): %sZła odpowiedź od Pushover (%s): %sZły harmonogram %s o %s:%sŹle zbudowany artykuł yEnc w %sPrzepustowośćZablokuj odświeżanie podczas wskazywaniaNa dółPrzeglądajModel procesoraUmieszcza artykuły w pamięci podręcznej, aby ograniczyć częstotliwość dostępu do dysku.
W bajtach, opcjonalnie z przyrostkiem K, M, G. Przykład: "64M" lub "128M"%s artykułów (%s)AnulujNie można zmienić uprawnień %sNie można połączyć się z serwerem %s [%s]Nie można utworzyć katalogu %s %sNie można utworzyć kopii zapasowej %sNie można utworzyć katalogu %sNie można utworzyć ostatecznego katalogu %sNie można utworzyć tymczasowego pliku dla %sBrak szablonów wiadomości email w %sNie znaleziono szablonu: %s, próbuję użyć standardowego szablonuNie można uruchomić przeglądarki, prawdopodobnie nie została znalezionaNie można połączyć się z usługą SABHelperNie można odczytać %sNie można odczytać obserwowanego katalogu %sNie można wysłać wiadomości, brak wymaganych danychNie można zapisać bazy danych historii, sprawdź prawa dostępu!Nie można zapisać pliku INI %sKategorieKategoriaNie zachowano zmian, zostaną one utracone.Zmiany wymagają restartu SABnzbd!Sprawdź wszystkieSprawdź przed pobraniemSprawdzaj aktualizacjeSprawdzanieInterwał sprawdzania (w minutach, co najmniej 15). Nieużywany podczas korzystania z harmonogramu!Wybierz skórkęLista czyszczeniaCzyszczenie %s nie powiodło się.WyczyśćWyzeruj licznikiKliknij znajdujący się poniżej przycisk Powtórz test, aby zmierzyćKliknij, aby przetestować wprowadzone daneZamknięcie okna przeglądarki lub karty NIE zamknie SABnzbd.Lista wartości oddzielonych przecinkamiKomentarzKatalog zakończonychSzybkość zapisu w katalogu zakończonychUkończoneKatalog dla ukończonych plikówKonfiguracjaPlik konfiguracyjnyKonfiguracjaPotwierdzaj usuwanie z historiiPotwierdzaj usuwanie z kolejkiPotwierdzoneBłąd połączenia %s@%s, komunikat=%sPołączenie udane!Połączenie nie powiodło się!PołączeniaSzerokość konteneraNie można określić wyniku połączenia (%s)Nie można rozpakować %sZapis nie powiódł się. Sprawdź uprawnienia katalogu do zapisu.Obecne harmonogramyWłasnyUDUPLIKATCodziennieKatalogi dzienneUszkodzona baza danych historii, utworzono w jej miejscu nową, pustąPanel głównySortowanie według datyFormat datyDzień miesiącaDekadaBłąd dekodowania %sDomyślneDomyślny katalog bazowyUsuńUsuńUsuń wszystkoUsuwanie zakończoneUsuwanie nie powiodło sięUsuń po pobraniuUsunąć z historii wszystkie ukończone pliki?Usunąć wszystkie pobrane pliki?Usunąć wszystkie obiekty z kolejki?Usunąć z historii wszystkie nieudane pliki?Usuwanie %s nie powiodło się!Działanie dla duplikatówWykryj zduplikowane odcinki serialiUrządzenieUrządzenie, do którego mają być wysyłane powiadomieniaUrządzenie(-a)Urządzenie(-a), do którego(-ych) mają być wysyłane powiadomieniaWyłącz zarządzanie limitemWyłączoneWyłączono HTTPS z powodu braku plików CERT oraz KEYOdrzućRozłącz serwer(y) Usenet kiedy kolejka jest pusta lub wstrzymanaRozłącz przy pustej kolejcePowiadomienie o pełnym dyskuBłąd dysku podczas tworzenia pliku %sDysk pełnyDysk pełny! Wstrzymuję pobieranieWykonuj dodatkową weryfikację na podstawie plików SFVBrak poprawnego uwierzytelnienia dla kanału %sCzy limit jest kasowany dziennie, tygodniowo czy miesięcznie?Nie masz dostawcy Usenet? Polecamy spróbować %s.NiżejPobierzZakończono pobieranieKatalog pobieraniaPobieranie nie powiodło sięPobierz wszystkie pliki par2Pobieranie nieudane - Dane niedostępne na skonfigurowanych serwerachSzybkość zapisu w katalogu pobieraniaPobieranie może się nie udać, dostępne jedynie %s z wymaganych %sPobranePobrano w %s ze średnią %sB/sPobieraniePobieranieDualView1DualView2Np.np. 8 lub 20ZASZYFROWANYBŁĄD:BŁĄD: %sBŁĄD: nieprawidłowa suma kontrolna CRC w "%s"BŁĄD: zbyt długa ścieżka (%s)BŁĄD: nie można znaleźć "%s"BŁĄD: błąd zapisu (%s)ETAEdycjaEdytuj szczegóły NZBBądź wstrzymaj, jeśliEmailPowiadomienia email po zakończeniu zadaniaAdresat wiadomości emailNadawca wiadomości emailWysłano email!Katalog szablonów emailAdres email, na który będą wysyłane powiadomieniaWiadomość wysłanaAwaryjnyBrakPusty plik NZB %sZnaleziono pusty wpis RSS (%s)WłączonyWłącz 7zipWłącz sortowanie według datyWłącz filtrowanieWłącz GrowlWłącz HTTPSWłącz sortowanie filmówWłącz NotifyOSDWłącz powiadomienia ProwlWłącz powiadomienia PushbulletWłącz powiadomienia PushoverWłącz sprawdzanie przy użyciu SFVWłącz sortowanie TVWłącz unzipWłącz powiadomienia WindowsWłącz dostęp do interfejsu przez HTTPSWłącz zmianę nazw katalogówWłącz, aby zmniejszyć użycie pamięci. Wyłącz, aby zapobiec blokowaniu kolejki przez powolne zadania.Włącz zarządzanie limitemWłącz rekursywne rozpakowywanieWłączonyZakończenie ścieżki znakiem gwiazdki (*) zapobiegnie tworzeniu katalogów dla zadań.Wprowadź URLTytuł odcinkaNumer odcinkaTytuł.odcinkaTytuł_odcinkaBłądBłąd "%s" podczas uruchamiania file_join na %sBłąd "%s" podczas wykonywania par2_repair na zestawie %sBłąd "%s" podczas uruchamiania rar_unpack na %sBłąd "%s" podczas uruchamiania unzip() na %sBłąd %s podczas uruchamiania par2_repair na zestawie %sBłąd %s: należy podać prawidłową nazwę użytkownika i hasło.Błąd tworzenia klucza i certyfikatu SSLBłąd pobierania informacji TV (%s)Błąd importu %sBłąd ładowania %s, wykryto uszkodzony plikBłąd podczas usuwania %sBłąd usuwania katalogu roboczego (%s)Błąd zmiany nazwy "%s" na "%s"Błąd podczas dodawania %s, usuwanieWyłączenie systemu nie powiodło sięTylko błędyBłąd: Długość ścieżki powinna być mniejsza niż %sBłąd: Kolejka nie jest pusta, nie można zmienić katalogu.Błąd: Nieprawidłowy klucz sesjiBłąd: Wymagany klucz sesjiBłędy/OstrzeżeniaWszystkoPrzykładWyjście z SABnzbdRozszerzenieDostęp z zewnątrzDodatkowe parametry PAR2Dodatkowa kolumna kolejkiRozpakowywanie...ODFILTROWANENieudaneBłąd logowania do serwera %sNie udało się utworzyć (%s)Nie udało się przenieść %s do %sBłąd uwierzytelnienia na serwerze pocztowymBłąd zamykania bazy danych, sprawdź logiNie udało się zamknąć połączenia z serwerem pocztowymBłąd kompilacji wyrażenia regularnego dla wyszukiwania: %sBłąd połączenia z serwerem pocztowymHibernacja systemu nie powiodła sięNie udało się zaimportować %s plików z %sBłąd podczas inicjalizacji %s@%s: %sBłąd połączenia TLSNie udało się przenieść plikówNie udało się zmienić nazwy podobnego pliku %s na %sNie udało się zmienić nazwy %s na %sNie udało się ponownie uruchomić NZB po wstępnym sprawdzeniu (%s)Nie udało się pobrać RSS z %s: %sBłąd wysyłania wiadomości ProwlBłąd wysyłania wiadomości emailNie udało się wysłać wiadomości PushbulletNie udało się wysłać wiadomości PushoverWstrzymanie systemu nie powiodło sięNie udało się uruchomić interfejsu WWWNie udało się uruchomić interfejsu WWW: NiepowodzenieBłąd w tempfile.mkstempBłąd krytycznyBłąd krytyczny podczas zapisywania stanuBłąd krytyczny w module składającymKanałPobierzPobierz NZB z URLPobieraniePobieranie %s bloków...Pobieranie dodatkowych bloków...Plik %s jest pusty, pomijamRozszerzenie plikuPlik zawierający wszystkie hasła, które będą używane do rozpakowywania zaszyfrowanych plików RARŁączenie pliku %s nie powiodło sięNazwa pliku lub ścieżka do certyfikatu HTTPSNazwa pliku lub ścieżka do łańcucha certyfikatów HTTPSNazwa pliku lub ścieżka do klucza HTTPSZestaw plikówNazwa plikuFiltrDziałania, które zostaną podjęte dla plików próbek (np. próbek wideo)PoczątekKatalog zawierający zdefiniowane przez użytkownika szablony powiadomień emailKatalog monitorowany w poszukiwaniu plików .nzb.
Skanowane są również pliki .zip, .rar oraz .tar.gz.Katalog/ŚcieżkaKatalogiNazwa konta dla kont z uwierzytelnieniemHasło dla kont z uwierzytelnieniemDla serwerów: zapewnij zgodność nazw z WindowsWymuśWymuś rozłączenieWymuś pobranieFormaty: .nzb, .rar, .zip, .gz, .bz2ForumWolne (tymczasowo)Wolne miejsceCzęstotliwośćPiątekOd SxxEyyPełne APIPełny interfejs WWWDalszą pomoc można uzyskać na naszejGBOgólneUtwórz nowy kluczPrzejdź do SABnzbdUruchom kreatora konfiguracjiGrowlPorty dla HTTP i HTTPS nie mogą być takie sameCertyfikat HTTPSŁańcuch certyfikatów HTTPSKlucz HTTPSPort HTTPSPomocHibernuj komputerUkryj opcje edycjiUkryj szczegółyPokaż/ukryj ukończone plikiWysokiHistoria10 ostatnichLimit wyświetlanych pozycji historiiPrzytrzymaj klawisz Shift, aby zaznaczyć zakresStartStrona projektuHostHost, na którym ma nasłuchiwać SABnzbdJak długo lub do kiedy chcesz wstrzymać? (po angielsku!)Ile danych można pobrać w miesiącu (K/M/G)BEZCZYNNYNIEKOMPLETNYParametry IONiceAdres IPv6IRCBezczynnyJeśli pole będzie puste, standardowy port będzie obsługiwał tylko HTTPSJeśli ponownie otrzymasz ten sam błąd, spróbuj zmienić numer portu.
Działanie dla próbekIgnoruj foldery wewnątrz archiwówIgnoruję zduplikowany NZB "%s"WJeśli wybrano "Wstrzymaj", będzie trzeba ustawić hasło i wznowić zadanieW razie ponownego uruchomienia SABnzbd ten ekran zniknie automatycznie!W katalogachPobieranie z Usenetu wymaga dostępu do dostawcy. Twój ISP może umożliwiać dostęp, aczkolwiek zalecany jest dostawca klasy premium.Niekompatybilny kanałZnaleziono niekompatybilny plik kolejki, nie można kontynuowaćKatalog niezakończonychNiekompletny plik NZB %sNiekompletna sekwencja plików do połączeniaNieprawidłowy opis kanału RSS "%s"Błędny parametrNieprawidłowa wartość %s: %sNieprawidłowo zakodowane hasło %sIdentyfikator indeksera (%s) nie został znaleziony w pliku ocenIndeksowanieNieprawidłowy plik NZB %s, pomijam (powód=%s, linia=%s)Nieprawidłowe kodowanie szablonu wiadomości email %sNieprawidłowy adres serwera.Niewłaściwe dane serweraNieprawidłowy log etapu w historii dla %sOdwróćZalecamy dodanie tej strony do zakładek i używanie tej zakładki do późniejszego dostępu do SABnzbd uruchomionego w tle.Zadanie nie powiodło sięZadanie ukończonePołącz plikiŁączenieTrzymaj niesklasyfikowane zadania w dodatkowych katalogachJęzykKoniecOstatnie ostrzeżeniaUruchom przeglądarkę podczas uruchamianiaUruchom domyślną przeglądarkę podczas uruchamiania SABnzbdOgranicz prędkośćOdnośnikiLista niepożądanych rozszerzeń. Przykład: exe lub exe, comLista rozszerzeń plików, które mają zostać usunięte po pobraniu.
Na przykład: nfo lub nfo, sfvLista zakresów sieci lokalnychŁadowanieNie udało się wczytać %sNie udało się wczytać %s: %sLokalny adres IPv4Lokalizacja bazy danych administracyjnych i historycznych kolejki.
Można zmienić tylko kiedy kolejka jest pusta.Lokalizacja logów SABnzbd.
Wymaga restartu SABnzbd!Miejsce przechowywania ukończonych, przetworzonych plików.
Może zostać zmienione przez ustawienia kategorii.Miejsce przechowywania nieprzetworzonych plików.
Można zmienić tylko kiedy kolejka jest pusta.Miejsce przechowywania plików .nzbKatalog logówLogowanieUtracono połączenie z SABnzbd...NiskiMałe literyMBKompatybilność z WindowsDopasowanoLimit prędkościMaksymalna przepustowość łączaMaksymalna ilość prób połączenia z serweremMaksymalna ilość próbZnaczenieMinimalna ilość wolnego miejsca w tymczasowym katalogu pobieraniaBrak klucza sesjiBrakujące artykułyŚredniPoniedziałekMiesiącWięcejWięcej ocen negatywnych niż pozytywnychTytuł filmuTytuł.FilmuTytuł_FilmuPrzenoszeniePrzenoszenie...Operacje na wieluEtykieta wieloczęściowaKlucz NZBNZB dodany do kolejkiNazwaSerwer DNSNazwyNigdyNowe wydanie %s dostępne naDostępne jest nowe wydanieDalejParametry niceBrak dostępuNie znaleziono szablonów wiadomości emailBrak katalogówPrzetwarzanie końcowe nie zostało uruchomione z powodu nieudanej weryfikacjiNie podano adresatów, wiadomość nie została wysłanaBrak wynikówNie znaleziono odpowiedniej metody uwierzytelnieniaBrakNormalnyNie dopasowanoNiedostępneNiewystarczająca ilość miejsca na dysku do ukończenia pobierania!NieużywaneNic nie zaznaczono!Centrum powiadomieńWysłano powiadomienie!PowiadomieniaNotifyOSDIlość sekund pomiędzy kolejnymi skanami w poszukiwaniu plików .nzbOPCJONALNE hasło do kontaOPCJONALNA nazwa kontaBrakWykryto kolejkę w starszej wersji, użyj funkcji Status->Naprawa, aby ją przekonwertowaćPo zakończeniuUżyj alternatywnego NZB w razie niepowodzeniaPo ukończeniu kolejkiW którym dniu miesiąca lub tygodnia (1=poniedziałek) twój dostawca resetuje limit pobierania (opcjonalnie z gg:mm)Pobieraj artykuły tylko dla pierwszego pliku w kolejceUruchom przetwarzanie końcowe tylko dla zadań, które zostały sprawdzone przy użyciu PAR2Tylko dla zdalnych serwerów Growl (host:port)Używaj tego serwera tylko dla tych kategoriiOtwórz URL informacyjnyOtwórz okno terminala i podaj linię (przykład):Otwórz katalog zakończonychOpcjonalnyOpcjonalne dodatkowe NZBOpcjonalne hasłoOpcjonalna nazwa użytkownikaOpcjonalne hasło dla serwera GrowlOpcjonalnie podaj nazwę plikuOpcjeLub przeciągnij i upuść pliki do okna!KolejnośćOryginalna nazwa plikuPorzucone zadaniaInneInne komunikatyInny problemPoza okresem przechowywaniaZATRZYMANEWeryfikacja %s nieudana, choć szybkie sprawdzenie powiodło się!ParametryNumer fragmentuHasłoPlik z hasłamiHasło ukryte za ******, proszę wprowadzić je ponownieZabezpieczone hasłemŚcieżkaCiągZastępowane ciągiWstrzymajWstrzymaj wszystkieWstrzymaj pobieranie podczas przetwarzania końcowegoWstrzymaj naWstrzymaj na 1 godzinęWstrzymaj na 15 minutWstrzymaj na 2 godzinyWstrzymaj na 30 minutWstrzymaj na 5 minutWstrzymaj na 6 godzinNa ile minut wstrzymać?Wstrzymaj na...Wstrzymaj zadania o wysokim priorytecieWstrzymaj zadania o niskim priorytecieWstrzymaj zadania o normalnym priorytecieWstrzymaj przetwarzanie końcoweWstrzymanoWstrzymuje pobieranie po rozpoczęciu przetwarzania końcowego i wznawia je po zakończeniuWstrzymuję zduplikowany NZB "%s"Procent przepustowości łączaUprawnienia dla ukończonych plikówPrywatny klucz APIPrywatny klucz API Prowl (wymagany)Notatki osobisteNazwa hosta 0.0.0.0 wymaga adresu IPv6 do dostępu z zewnątrzPodaj szczegóły swojego głównego dostawcy UsenetPortPort, na którym ma nasłuchiwać SABnzbdPrzetwarzanie końcowe nie powiodło się dla %s (%s)Przetwarzanie końcowePrzetwarzanie końcowe tylko dla zweryfikowanych zadańPrzetwarzanie końcoweUruchomiono przetwarzanie końcowePrzetwarzanie końcowe zostało przerwane (%s)Skrypt użytkownika przed zakolejkowaniemPredefiniowaneNaciśnij Klawisz start+R i podaj linię (przykład):WsteczZapobiegaj równoważeniu obciążeniaWsteczPriorytetPrawdopodobne współdzielenie kontaProblem zPrzetworzony ciągPrzetwarzanieProgram się nie uruchomił!PostępProwlPubliczny adres IPv4WyczyśćWyczyść ukończone NZBWyczyść nieudane NZBWyczyść nieudane NZB i usuń plikiWyczyść historięWyczyść NZBWyczyść NZB i usuń plikiCzyszczenie kolejkiWyczyścić historię?Wyczyścić kolejkę?PushbulletPushoverWersja PythonaKolejkaZakolejkuj 10 pierwszychKolejka ukończonaLimit wyświetlanych pozycji kolejkiNaprawa kolejkiSzybkie sprawdzanie...Szybkie sprawdzanieZakończLimit pobieraniaPozostało limituOkres limituPrzekroczono limit, wstrzymywanie pobieraniaNRSSInterwał sprawdzania RSSKanał RSS %s był pustyUruchomiono %sZakresRzadko używane opcje. Jeśli chcesz się dowiedzieć, co oznaczają, kliknij przycisk Pomoc, aby przejść do strony Wiki.
Nie zmieniaj tych opcji bez uprzedniego przeczytania Wiki, ponieważ niektóre mają poważne skutki uboczne.
Domyślne wartości zostały umieszczone w nawiasach.Czytaj teraz wszystkie kanałyPobierz kanałCzytaj kanały RSSCzytaj wszystkie kanały RSSPrzeczytaj o tym w Wiki!OdświeżCzęstotliwość odświeżaniaCzęstotliwość odświeżaniaOdrzućŚcieżki względne w stosunku doPozostałoUsuń NZBUsuń NZB i plikiUsuń serwerUsuń wszystkie zaznaczone plikiUsuń ukończone zadaniaUsuń nieudane zadaniaUsuwanie %s nie powiodło sięZmień nazwęNaprawaNaprawa nie powiodła się, brak wystarczającej ilości bloków naprawczych (brakuje %s)NaprawianieNaprawa nie powiodła się, %sNaprawianie...Powtórz testZastąp spacje w nazwach katalogówZastąp kropki w nazwach katalogówZastąp kropki w nazwach katalogów spacjamiZastąp spacje w nazwach katalogów podkreśleniamiZgłośWymagaWymaga konta ProwlWymaga konta PushbulletWymaga konta PushoverWymagaKatResetujResetuj limitDzień resetuUruchom ponownieUruchom ponownie SABnzbdRestart bez logowaniaRestartowanie SABnzbd...WynikWznówWznów zadania o wysokim priorytecieWznów zadania o niskim priorytecieWznów zadania o normalnym priorytecieWznów przetwarzanie końcoweWznawianieCzas przechowywaniaPonówPonów wszystkiePonów wszystkiePonów wszystkie nieudanePonów wszystkie nieudane zadaniaPonowić wszystkie nieudane zadania z historii?Ponowić wszystkie nieudane zadania?Uruchamianie skryptuWykonywanie skryptu...Uruchamianie skryptu użytkownika %sKatalog odcinka S01E05Katalog sezonu S01E05Uruchomiono SABnzbd %sAdres hosta SABnzbdHasło SABnzbdPort SABnzbdSzybki kreator konfiguracji SABnzbdUżytkownik SABnzbdWersja SABnzbdSerwer WWW SABnzbdSABnzbd wykrył krytyczny błąd:SABnzbd został wyłączonySABnzbd będzie uruchomiony w tle.Serwer SMTPBłąd polecenia SQL, sprawdź logiSSLSobotaZapiszZapisz zmianyZapisanoNie udało się zapisać %sZapisywanie...Przeszukaj obserwowany katalogHarmonogram dla nieistniejącego serwera %sHarmonogramSkryptKod zakończenia skryptu: %sSkryptySzukajNumer sezonuWybierz język interfejsu WWWZaznacz tylko jeśli twój dostawca zezwala na połączenia SSLZaznaczenieWyślijWyślij GROUPPowiadomienia RSSWyślij z powrotem do kolejkiPowiadom, kiedy kanał RSS dodaje zadanie do kolejkiPowiadom, kiedy dysk jest pełen, a SABnzbd wstrzymanyWyślij polecenie GROUP przed żądaniem artykułuWysyłaj powiadomienia GrowlWysyłaj powiadomienia do centrum powiadomieńWysyłaj powiadomienia do NotifyOSDWysłano %s do kolejkiSortowanie serialiSerwerSerwer %s wymagania podania nazwy użytkownika i hasłaSerwer %s używa niezaufanego certyfikatu HTTPSSerwer %s będzie ignorowany przez %s minutSzczegóły serweraAdres serweraNieprawidłowy adres serwera "%s:%s".Wymagane jest podanie adresu serweraOpis serweraRównoważenie obciążenia serwerówNie udało się rozwiązać nazwy serweraHasło serweraSerwer przerwał połączenie w trakcie logowania.Serwer wymaga podania nazwy użytkownika i hasła.Błąd po stronie serwera (kod: %s); nie udało się pobrać %s z %sSerweryUstawienia podane uprawnienia dla pobranych plików/katalogów.
W notacji ósemkowej. Przykład: "775" lub "777"Ustaw serwer swojego ISP dla poczty wychodzącejKonfiguracja ukończona!Czy pobieranie powinno zostać automatycznie wznowione w dniu resetuPokaż wszystkoPokaż opcje edycjiPokaż nieudanePokaż logiTytuł serialuKatalog z tytułem serialuPokaż aktywne połączeniaPokaż szczegółyPokaż interfejsTytuł.serialuTytuł_serialuWyświetlanie wyników %s-%s z %sPokazuję jeden wynikZakończWyłącz komputerWyłącz SABnzbdWyłączanieOdebrano sygnał %s, zapisywanie i zamykanie programu...RozmiarWeryfikacja niektórych plików względem "%s" nie powiodła sięNiektóre serwery udostępniają alternatywne NZB, kiedy pobieranie kończy się niepowodzeniemPrzykro mi, nie rozumiem. Spróbuj ponownie.SortujWzorzec sortowaniaSortuj według wiekuSortuj według wieku (Najnowsze→Najstarsze)Sortuj według wieku (Najstarsze→Najnowsze)Sortuj według wieku Najnowsze→NajstarszeSortuj według wieku Najstarsze→NajnowszeSortuj według nazwy (A→Z)Sortuj według nazwy (Z→A)Sortuj według nazwy A→ZSortuj według nazwy Z→ASortuj według rozmiaru (Największe→Najmniejsze)Sortuj według rozmiaru (Najmniejsze→Największe)Sortuj według rozmiaru Największe→NajmniejszeSortuj według rozmiaru Najmniejsze→NajwiększeSortowanieŹródłoSpamSpecjalnePrędkośćLimit prędkościOgranicz prędkośćUśpij komputerUruchom kreatora konfiguracjiRozpoczynanie naprawyUruchomienie/WyłączenieStatusStan i opcje interfejsuStopZatrzymywanie...TematWyślijWysłano. Dzięki!NiedzielaNieobsługiwany błąd w module pobieraniaPrzełącznikiObciążenieKatalogi systemoweWydajność systemu (Pystone)TEKSTZA DUŻYZadanieFolder tymczasowyTymczasowy katalog pobieraniaPrzetestuj emailPowiadomienie testoweTestuj serwerTestuję serwer...Przycisk "Napraw" ponownie uruchomi SABnzbd i spowoduje kompletne
odtworzenie zawartości kolejki, z zachowaniem już pobranych plików.
Kolejność elementów kolejki zostanie zmieniona.Automatyczne narzędzie do pobierania z UsenetuPole wyboru obok nazwy kanału musi być zaznaczone, aby kanał był włączony i automatycznie sprawdzany w poszukiwaniu nowych wpisów.
Po dodaniu kanału będą pobierane tylko nowe wpisy - żaden istniejący już w kanale RSS wpis nie zostanie pobrany, chyba że klikniesz przycisk "Wymuś pobranie".Nie ustawiono nazwy hosta.Ilość połączeń dopuszczanych przez twojego dostawcęSerwer nie odpowiedział poprawnie na polecenie HELONie ustawiono maksymalnej liczby połączeń. Proszę umożliwić przynajmniej jedno połączenie.W katalogu pobierania istnieją porzucone zadania.
Możesz je usunąć (razem z plikami) lub wysłać z powrotem do kolejki.Ten klucz umożliwi innym programom dodawanie plików NZB do SABnzbdTen klucz umożliwi innym programom dostęp do SABnzbdTen miesiącSerwer nie obsługuje SSL na tym porcieTen tydzieńBlokuje odświeżanie zawartości po najechaniu kursorem na kolejkęSABnzbd zostanie zrestartowane.
Użyj tej funkcji jeśli uważasz, że program ma problemy ze stabilnością.
Pobieranie zostanie wstrzymane przed restartem i wznowione po ponownym uruchomieniu.Nastąpi wysłanie testowej wiadomości na twoje konto.CzwartekUpłynął limit czasu odpowiedzi.Upłynął limit czasu odpowiedzi: spróbuj włączyć SSL lub połącz się z innym portem.PozostałoLimit czasu odpowiedziTytułSłowa kluczowe w tytuleTo: %s From: %s Date: %s Subject: SABnzbd zgłasza przekroczenie dopuszczalnej zajętości dysku Cześć, SABnzbd przestał pobierać pliki, ponieważ dysk jest prawie pełen. Opróżnij trochę miejsca i wznów działanie SABnzbd ręcznie. DzisiajPokaż/ukryj panel dodawania NZBZbyt mało miejsca na dysku, wymuszanie WSTRZYMANIAZbyt wiele połączeń do serwera %sZbyt wiele połączeń, proszę wstrzymać pobieranie lub spróbować ponownie późniejNa góręGórne menuRazemRozwiązywanie problemówWypróbuj naszą nową skórkę, Glitter! Zupełnie nowy, świeży projekt zoptymalizowany dla komputerów stacjonarnych i urządzeń przenośnych. Skórkę możesz zmienić w sekcji Konfiguracja->Ogólne.Spróbuj przewidzieć, czy pobieranie będzie udane przed jego rozpoczęciem (wolne!)Próba rozpakowania archiwum 7zip z użyciem hasła "%s"Próba weryfikacji SFVPróba pobrania NZB z %sPróba ustawienia statusu nieistniejącego serwera %sPróba rozpakowania archiwum RAR z użyciem hasła "%s"WtorekStrojenieTypRŚcieżka UNC "%s" niedozwolonaNIEPOŻĄDANYPobieranie URL nie powiodło się; %sDziałanie modułu pobierania URL zostało przerwaneDostęp zabronionyOdblokujNiezdefiniowany serwer!Nieznany błąd podczas dekodowania %sNieznane działanie: %sUwierzytelnienie na serwerze pocztowym nie powiodło się z nieznanej przyczynyRozpakujRozpakowuj archiwa (rar, zip, 7z) wewnątrz archiwówZbyt głęboki poziom zagnieżdżenia podczas rozpakowywania [%s]Rozpakowano %s plików/katalogów w %sRozpakowywanieRozpakowywanie nie powiodło się, %sRozpakowywanie nie powiodło się, błąd CRCRozpakowywanie nie powiodło się, archiwum wymaga podania hasłaRozpakowywanie nie powiodło się, zbyt długa ścieżkaRozpakowywanie nie powiodło się, sprawdź logiRozpakowywanie nie powiodło się, nie można znaleźć %sRozpakowywanie nie powiodło się, błąd zapisu lub zapełniony dysk?Bezużyteczny plik NZBBezużyteczny plik RARNiepożądane rozszerzenie w pliku RAR %sNiepożądane rozszerzeniaWyżejDostępna aktualizacja!WczytajWczytaj NZBWczytaj: .nzb, .rar, .zip, .gz, .bz2Czas działaniaUżyj globalnych ustawień interfejsuUżywaj tymczasowych nazw podczas przetwarzania końcowego. Należy wyłączyć tę opcję, jeśli system nie obsługuje jej prawidłowo.Uruchamiany zanim plik NZB zostanie umieszczony w kolejceUżyta pamięć podręcznaPrzydatne, gdy serwer ma więcej niż jeden adres IPv4/IPv6Katalogi użytkownikaKlucz użytkownikaKlucz użytkownika (wymagany)Skrypty użytkownika mogą oznaczyć zadanie jako nieudaneNazwa użytkownikaWartościPoprawnie zweryfikowano z użyciem plików SFVWeryfikowanieWeryfikowanie...WersjaBardzo niskiWideoOcena wideoZobacz log skryptuWirus/spamCZEKAM %s sUWAGA:UWAGA: Zadanie "%s" zostało przerwane z powodu oceny (%s)UWAGA: Plik z niepożądanym rozszerzeniem wewnątrz pliku RAR "%s". Niepożądany plik to %s UWAGA: Zadanie "%s" zostało wstrzymane z powodu oceny (%s)OczekujeOstrzeżenieUwaga: LOCALHOST jest niejednoznaczne, użyj adresu IP.OstrzeżeniaObserwowany katalogCzęstotliwość skanowania katalogu obserwowanegoInterfejs WWWŚrodaSprawdzaj co tydzień dostępność nowych wydań SABnzbdKiedyJeśli podczas pobierania okaże się, że brakuje zbyt dużej ilości danych, przerwij zadanieJeśli skrypt użytkownika zwróci niezerowy kod zakończenia, zadanie zostanie oznaczone jako nieudaneJaki procent dostępnej przepustowości ma wykorzystywać SABnzbd, np. 50Kto powinien być nadawcą wiadomości email?WikiPowiadomienia WindowsSzybkość zapisuXRokKatalogi rok-miesiącPlush wymaga włączenia obsługi JavaScript!Przed ustawieniem limitu przepustowości należy ustawić maksymalną przepustowośćTwoja wersja unrar to %s, zalecana jest wersja %s lub wyższa.
Prywatny klucz API Pushbullet (wymagany)[%s] Błąd "%s" podczas łączenia plików[%s] Błąd "%s" podczas rozpakowywania plików RAR[%s] Połączono %s plików[%s} Brak zestawów par2[%s] PAR2 otrzymał nieprawidłowe opcje, sprawdź ustawienia w sekcji Konfiguracja->Przełączniki[%s] Szybkie sprawdzenie OK[%s] Naprawiono w %s[%s] Zweryfikowano w %s, wszystkie pliki prawidłowe[%s] Zweryfikowano w %s, wymagana naprawaModuł _yenc... NIE znaleziono!artykułówaudioz dostosowaniem wielkości literwyczyśćddzieńdniwyłącz serwerźle ocenianewłącz serwerplikggodzinagodzinysłowa kluczowepozostałomręcznieminutamin.minutnie zainstalowanezwyłączonewłączonelublub mniejstronaProgram par2 ... NIE znaleziono!zabezpieczone hasłemsekundasekundsprawdź logispamtekstnieznanyProgram unrar ... NIE znaleziono!Program unzip ... NIE znaleziono!wideotydzieńSABnzbd-2.3.2/locale/pt_BR/LC_MESSAGES/SABnzbd.mo0000644000000000000000000022135513217005256017012 0ustar 00000000000000|>o>dM?@ ABCD*D'DEE5E NEoE~EE EEEFFFFFF1FFG*G>GWG?GH H0H8HRHH[HH II#IV(TV}V V-VVV#Wh$Mhrh xh h hh hhh hhhh i i i'&iNi`i xi ii ii iiiiii j/j 4j>jCj;bj-jj jj jjj6kG;kk"kkkEkDl _ljlm,mBmTm%km#mmmm*n/n28n%knnn'nnn zo o oo%ooooo5p 9pEpHKpnpq q(q:qZqcmqHqor]r)r ss%sBs FsQsTsls ts~s$sss0sst$t-t4t:t?t Xt ct ntyt tttttttttt u#u(u 8uBu [u1fu"u u+uuu u v,vEvNv`vtv v v/vvvw;w CwMwmwc}w"wAx,Fx*sxx3xxxy!!y!Cy"eyyy%yyy yyz zz.z45z jz uzz z*z zzz zz z(z {*{;{P{b{w{{{ {{{{|(|M/|}||#||%| }R}<n}}}"}}~"~2~J~j~~-~~~~~~ ~  &=FL`f{     %4:O^ o| ހ ",;Nj r  Ƃ 1DK2R  ڃ)0PW`y ń Մ߄ #*1Kd Ʌڅ!)8Jaw  ʆ9.S  ɇχ# !,3JR Y g4 Lj ̈׈335.i)މ %-F(t$ !>"N&q:Ӌoۋ)Ku3Ɍ ی  '4 C M"Wz  '(>.V //Ҏ--0&^&$$я33*1^1ʐѐ֐ސ #4;X ]iqx‘ё   (3 EQk"?@2Y5A”>=ȕ + =WG,Dq z>×̗ԗڗ"!՘A9=F LYE)H`.|˚Ӛښߚ !4HPb-Û/ʛ 7AV-r"Ü#ݜ.0B$Ty ՝ܝb$] : Ȟ՞ޞ"%% K Ubjs y 0E/-]e:m ڠ %RUp=ơ!&+ AOQV1iEB+$#P)tJţ$&8'_ ŤǤˤФ ߤ   $) .<?CFIQV p{ ڥ^f$m 213Oj!)  ǯίׯ ;BZ>r"԰O\ ˱ձamGʲ Ӳ.%!63X) ̳7ӳC *O0z  ϴݴ -BV\,bU;A\c#x++ ,G _ ju|4oǷ7O;)+2)9'c!˹ܹ +ź.$ 4E"z(6ƻ3L1H~1Ǽ.5ATw*̽ 4 ,An \.?W^2p*Bο .:O mx" &AW hr:"Q8 LZ \ fr;  "*@G P^s2# /E_(} 14( H4S M( DP6m.44 =HQew4IF#Os |   ')DMTk~,,5 P\e!z !5#Q!u( 2 ?^_ [ ^k}%0& #3.WE%&1-_(r/ C9 }#  ) >KT[y,0$:*'e#6$-<j8#!:$\ !  #(.DLazT!4&+[.88$s] /'L>%   + 5B'Y) " .: @Nk"| 1 (8(=@f*  ?QR GN> CEV,&$9"U<x 7. (I1i): LZ.a/Qyh! -$RgXFo/E u  +< R;^ %  "- 5@R fp " 6:A1|:A'ix <"( KTU *{(pZ83-a7w!$$3-X&"B+ n{+  /CL^t !"2UqOy!&.+@la{A#%(Ir.' +4;pt #   %=F]'r   -2N^v#  !1 L Ycv ( !$F O[z& C Wa x $"06 CLS j   2 <#F$j%  &23Y% /CSd(u"/ P$^ + "!)KSY)n9   ;&Eb34%0Vn!4+&.<!k" -!)LK |(  I9j   (9 J W"d  )1G7<==+;i;** (7(`5533)  ]  i w |           9  ? J R Y l t           ( 6 M  ] ~ .3 #b ! 2 B HgKBA * `&3 I,v  sx-#N2 7EKdG;Zu4&   )  6A[y #: +:87s'&4'3\%::,F.`    ) s4)9 ( :7[,   2=RAYV= 0;=B.  0XqwO'9af}7QJ3*~$. L/ |  1 - !!0!8!?!U!\!^!b!g!|!!!!!!! !!!!!!!! !""""#""F"Z"^"g"}"" "$"$""" SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Also test releasesAlwaysApplication TokenApplication token (required)Apply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentComplete FolderComplete folder speedCompletedCompleted Download FolderConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDisable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDualView1DualView2E.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra queue columnExtracting...FILTEREDFailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.ForceForce DisconnectForce DownloadFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGo to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHelpHibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIndexer id (%s) not found for ratings fileIndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job failedJob finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocation for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMeaningMinimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateMondayMonthMoreMore thumbs down than upMovie NameMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelNZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification Sent!NotificationsNotifyOSDNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Pre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...ResultResumeResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScriptsSearchSeason NumberSelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...SubjectSubmitSubmitted. Thank you!SundaySuspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUnauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UptimeUse global interface settingsUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User script can flag job as failedUsernameValuesVerified successfully using SFV filesVerifyingVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen the user script returns a non-zero exit code, the job will be flagged as failed.Which percentage of the linespeed should SABnzbd use, e.g. 50Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2016-01-01 22:58+0000 Last-Translator: lrrosa Language-Team: Brazilian Portuguese MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:31+0000 X-Generator: Launchpad (build 18511) SABnzbd não pode encontrar seus arquivos da interface web em %s.
Por favor instale o programa novamente.

SABnzbd detectou dados salvos de outra versão do SABnzbd
mas não pode reutilizar os dados do outro programa.

Você pode querer terminar sua fila antes com o outro programa.

Após isso inicie este programa com a opção "--clean".
Isto irá apagar a fila atual e histórico!
SABnzbd leu o arquivo "%s". SABnzbd detectou que o arquivo sqlite3.dll está faltando.

Alguns anti-vírus mal projetados removem este arquivo.
Por favor, verifique o seu anti-vírus, tente reinstalar o SABnzbd e reclame com o seu fornecedor de anti-vírus.

SABnzbd precisa de uma porta tcp/ip livre para seu servidor web interno.
A porta %s em %s foi tentada, mas não está disponível.
Algum outro software usa a porta ou o SABnzbd já está rodando.

Por favor reinicie o SABnzbd com um número de porta diferente. SABnzbd precisa de um endereço de host válido para seu servidor web interno.
Você especificou um endereço inválido.
Valores seguros são localhost e 0.0.0.0

Por favor reinicie o SABnzbd com um endereço de host correto. SABnzbd não possui QUALQUER GARANTIA. É software livre, e você está convidado a redistribuí-lo sob certas condições. Está licenciado sob a LICENÇA PÚBLICA GERAL GNU Versão 2 ou (a seu critério) qualquer versão posterior. %s -> Codificação desconhecida%s => faltando em todos os servidores. Descartando%s artigos tinham duplicatas não-correspondentes%s artigos estavam malformados%s artigos estavam faltando%s artigos foram removidospasta %s: %s erro de acesso%s arquivos em %s%s não é um valor octal correto%s não é um endereço de e-mail válidofaltando %s Resolvendo endereço 
Encerramento do SABnzbd concluído.
Espere cerca de 5 segundos e, em seguida, clique no botão abaixo.

Atualizar
+ Debug+ Info+Excluir+Reparar+DescompactarPasta de Backup de .nzb0 é a prioridade mais alta, 100 é a prioridade mais baixa1x05 Pasta Do Episódio1x05 Pasta Da TemporadaO arquivo 7ZIP "%s" está incompleto, impossível descompactaraplicativo 7za... NÃO encontrado!NOTA: Pastas serão criadas automaticamente ao salvar. Você pode usar caminhos absolutos para salvar fora das pastas padrão.Dados não serão movidos. Será necessário reiniciar o SABnzbd!IDADEAPI (sem Configuração)Chave APIAPI Key QR CodeChave de API incorreta. Use a chave de API de Configuração->Geral em seu programa de terceiros:Chave de API faltando. Por favor insira a chave de API de Configuração->Geral em seu programa de terceiros:Chave API para ProwlCancelarInterrompa seCancela tarefas que não podem ser concluídasCancelado, não é possível concluirCancelado, criptografia detectadaInterrompido, filtro de pontuação encontrado (%s)Cancelado, extensão indesejada detectadaAceitarAcesso negadoAçãoAção faz o download de acordo com as regras de filtroAção quando uma extensão indesejada é detectada em arquivos RARAção quando RAR criptografado é baixadoAção quando extensão indesejada for detectadaAçõesAdicionarAdicionar ArquivoAdicionar NZBAdicionar arquivos NZB Adicionar AgendamentoAdicionar ServidorNZB AdicionadoPasta AdministrativaCategorias AfetadasIdadeTodosTodos os arquivos irão em uma única pasta.Todas os endereços da rede local começam com esse prefixo (geralmente "192.168.1.")Permitir balanceamento de cargaPermitir balanceamento de carga com optimização para IPv6Também versões de testesSempreToken da aplicaçãoToken da aplicação (obrigatório)Aplicar aos SelecionadosTem certeza que deseja reiniciar o SABnzbd?Tem certeza de que quer encerrar o SABnzbd?Você tem certeza?ParâmetrosLimite de Cache de ArtigosIdentificador de artigoNo mínimoNo máximoÁudioPontuação do áudioFalha de autenticação, verifique usuário / senha.Autenticação faltando. Por favor insira usuário/senha de Configuração->Geral em seu programa de terceiros:Retomar automaticamentePausar automaticamente quando o espaço livre estiver abaixo deste valor.
Em bytes, opcionalmente seguido de K,M,G,T. Por exemplo: "800M" ou "8G"Classificar automaticamente os itens por (média de) idade.BVoltarBackupResposta incorreta do Pushbullet (%s): %sResposta incorreta do Pushover (%s): %sAgendamento %s incorreto em %s:%sArtigo yEnc mal formado em %sLargura de bandaImpedir Atualizações no FocoBaseNavegarModelo da CPUManter artigos em memória para reduzir o acesso a disco.
Em bytes, opcionalmente seguido de K,M,G. Por exemplo: "64M" ou "128M"%s artigos em cache (%s)CancelarNão é possível alterar permissões de %sNão é possível conectar ao servidor %s [%s]Não foi possível criar %s pasta %sNão é possível criar um arquivo de backup para %sNão é possível criar a pasta %sNão é possível criar a pasta final %sNão é possível criar um arquivo temporário para %sNão é possível encontrar modelos de e-mail em %sNão foi possível encontrar o template web: %s. Tentando o template padrãoNão é possível iniciar o navegador. Provavelmente não foi encontradoNão foi possível localizar o serviço SABHelperNão é possível ler %sNão é possível ler a Pasta de Assistidos %sNão foi possível enviar, faltam dados obrigatóriosNão é possível gravar os dados de histórico, verifique as permissões de acesso!Não é possível gravar no arquivo INI %sCategoriasCategoriaAs alterações não foram salvas e serão perdidas.Mudanças exigirão um reinício do SABnzbd!Selecionar todosVerifique antes de baixarProcurar por nova versãoVerificandoIntervalo de verificação (em minutos, ao menos 15). Inativo quando você usar o Agendador!Escolha uma skin.Lista de LimpezaA limpeza de %s falhou.LimparLimpar ContadoresClique no botão de Repetir abaixo para determinarClique para testar os detalhes informados.Fechar qualquer janela/aba do navegador NÃO vai fechar o SABnzbd.Lista separada por vírgulasComentárioPasta de FinalizadosCompletar velocidade da pastaConcluídoPasta de Downloads ConcluídosConfiguraçãoArquivo de ConfiguraçãoConfiguraçãoConfirmar Exclusões do HistóricoConfirmar Exclusões da FilaConfirmadoA conexão a %s@%s falhou. Mensagem=%sConexão com Sucesso!Conexão falhou!ConexõesLargura do ContêinerNão foi possível determinar o resultado da conexão (%s)Não foi possível descompactar %sNão foi possível escrever. Verifique se o diretória tem permissão de escrita.Agendamentos AtuaisPersonalizadoDDUPLICADODiariamentePastas DiáriasDados de histórico danificados, criado um substituto vazioPainel de controleOrdenação por dataFormato da dataDia do mêsDécadaFalha ao decodificar %sPadrãoPasta Inicial PadrãoApagarEliminarExcluir TodosExclusão ConcluídaFalha na ExclusãoExcluir após downloadEliminar do histórico todos os itens concluídos?Excluir todos os arquivos baixados?Eliminar todos os itens da fila?Excluir do histórico todos os itens com falha?A exclusão de %s falhou!Detectar Downloads DuplicadosDetecta episódios duplicados em sériesDispositivoDispositivo para qual a mensagem deve ser enviadaDispositivo(s)Dispositivo(s) para qual a mensagem deve ser enviadaDesativar gerenciamento de cotaDesativadoHTTPS desabilitado pela falta de arquivos CERT e KEYDescartarDesconecte do(s) servidor(es) Usenet quando a fila estiver vazia ou pausada.Desconecte quando fila vaziaNotificações de Disco CheioErro de disco na criação do arquivo %sDisco cheioDisco cheio! Forçando PausaFazer uma verificação extra baseada em arquivos SFV.Não há autenticação válida para o feed %sA quota é restabelecida a cada dia, semana ou mês?Não tem um provedor usenet? Recomendamos testar %s.Para baixoDownloadDownload concluídoPasta de DownloadO download falhouBaixar todos os arquivos PAR2O download falhou - Não está em seu(s) servidor(s)Velocidade de download da pastaO download pode falhar. Somente %s de %s necessários estão disponíveisBaixadosBaixado em %s a uma média de %sB/sBaixandoDownloadsDualView1DualView2Ex.Ex: 8 ou 20CRIPTOGRAFADOERRO:ERRO: %sERRO: CRC falhou em "%s"ERRO: caminho muito extenso (%s)ERRO: Não foi possível encontrar "%s"ERRO: erro de escrita (%s)EstimadoEditarEditar Detalhes do NZBOu então pause seE-mailNotificar por e-mail na conclusão da tarefaDestinatário do E-mailE-mail do RemetenteEmail Enviado!Pasta de Modelos de E-mailEndereço de e-mail para receber os e-mails.E-mail enviado com sucessoEmergencialEsvaziarArquivo NZB %s vazioEntrada RSS vazia encontrada (%s)HabilitarAtivar 7zipAtivar a ordenação por dataHabilitar filtrosHabilitar GrowlHabilitar HTTPSAtivar a ordenação de filmesHabilitar NotifyOSDAtivar notificações ProwlHabilitar notificações PushbulletHabilitar notificações PushoverHabilitar verificações baseadas em SFVAtivar a ordenação de TVHabilitar UnzipHabilitar notificações WindowsAtivar acesso à interface por um endereço HTTPS.Habilitar renomeação de pastaAtive para menor uso de memória. Desative para impedir que trabalhos lentos bloqueiem a fila.Ativar gerenciamento de cotaAtiva descompactação recursivaAtivoPara evitar a criação de pastas de trabalho, adicione um asterisco (*) depois do caminho.Digite a URLNome do EpisódioNúmero do EpisódioNome.EpisódioNome_EpisódioErroErro "%s" ao executar file_join em %sErro "%s" ao executar par2_repair no conjunto %sErro "%s" ao executar rar_unpack em %sErro "%s" ao executar unzip() em %sErro %s ao executar par2_repair no conjunto %sErro %s: Você precisa fornecer um nome de usuário e senha válidos.Erro ao criar chave SSL e certificadoErro ao obter informações de TV (%s)Erro ao importar %sErro ao carregar %s. Arquivo corrompido detectadoErro ao remover %sErro ao remover a pasta de trabalho (%s)Erro ao renomear "%s" para "%s"Erro ao adicionar %s. RemovendoErro ao desligar o sistemaSomente para errosErro: Tamanho do caminho deve ser menor que %s.Erro: A fila não está vazia. Não será possível mudar de pasta.Erro: chave de sessão incorretaErro: chave de sessão obrigatóriaErros/AvisosTudoExemploSair do SABnzbdExtensãoAcesso externo da InternetParâmetros Extras PAR2Coluna extra da filaExtraindo...FILTRADOFalhouFalha de logon ao servidor %sFalha ao criar (%s)Falha ao mover %s para %sFalha ao autenticar com o servidor de e-mailFalha ao fechar o banco de dados. Consulte o logFalha ao fechar a conexão de e-mailFalha ao compilar a expressão para o termo pesquisado: %sFalha ao conectar ao servidor de e-mailFalha ao hibernar o sistemaFalha ao importar %s arquivos de %sFalha ao iniciar %s@%s devido as seguintes razões: %sFalha ao iniciar a conexão TLSFalha ao mover arquivosFalha ao renomear arquivo similar: %s para %sFalha ao renomear: %s para %sFalha ao renicializar NZB após a pre verificação (%s)Falha ao obter RSS de %s: %sFalha ao enviar mensagem ProwlFalha ao enviar o e-mailFalha ao enviar mensagem pushbulletFalha ao enviar mensagem pushoverFalha ao colocar o sistema em esperaFalha ao iniciar a interface webFalha ao iniciar a interface web FalhaFalha em tempfile.mkstempErro fatalErro fatal ao salvar estadoErro fatal no AssemblerFeedObterBuscar NZB de uma URLObtendoObtendo %s blocos...Obtendo blocos extras...Arquivo %s está vazio. PulandoExtensão do arquivoArquivo contendo todas as senhas que serão testadas em arquivos RAR criptografados.A união de arquivos de %s falhouNome do arquivo ou caminho para o certificado HTTPS.Nome de arquivo ou caminho da Cadeia HTTPS.Nome do arquivo ou caminho para a chave HTTPS.Conjunto de arquivosNome do arquivoFiltroExclui arquivos de amostra. Exemplo: amostras de vídeo.PrimeiraPasta contendo modelos de e-mail definidos pelo usuárioPasta para monitorar por arquivos .nzb.
Também procura arquivos .nzb em arquivos .zip, .rar e .tar.gz.Pasta/CaminhoPastasNome da conta, para e-mails com autenticação.Senha, para e-mails com autenticação.Para servidores: tenha certeza que os nomes são compatíveis com o Windows.ForçarForçar DesconexãoForçar DownloadFormatos: .nzb, .rar, .zip, .gz, .bz2FórumDisponível (Temporário)Espaço DisponívelFrequênciasexta-feiraDe SxxEyyAPI completaInterface Web completaMais ajuda pode ser encontrada em nossoGBGeraisGerar Nova ChaveIr para o SABnzbdIr para o assistenteGrowlPortas HTTP e HTTPS não podem ser iguaisCertificado HTTPSCadeia de Certificados HTTPSChave HTTPSPorta HTTPSAjudaHibernar o PCOcultar Opções de EdiçãoOcultar detalhesEsconder/Exibir arquivos completosAltaHistóricoHistórico dos últimos 10 itemsLimite de itens no históricoSegure a tecla shift para selecionar um intervaloInícioPágina inicialHostComputador onde o SABnzbd ficará ativo.Por quanto tempo ou até quando você quer pausar? (em Inglês!)Quanto pode ser baixado neste mês (K/M/G)OCIOSOINCOMPLETOParâmetros IONiceEndereço IPv6IRCInativoSe estiver vazio, a porta padrão só irá funcionar com HTTPS.Se você receber esta mensagem de erro outra vez, tente um número diferente.
Ignorar amostrasIgnorar qualquer pasta arquivadaIgnorando NZB duplicado "%s"EmEm caso de "Pausa", você precisa definir uma senha e retomar a tarefa.No caso de reinício do SABnzbd, esta janela irá desaparecer automaticamente!Em pastasPara baixar a partir da usenet você precisa ter acesso a um provedor. Seu provedor de Internet pode fornecer-lhe acesso, no entanto, um provedor exclusivo é recomendado.Feed incompatívelEncontrado arquivo de fila incompatível. Não é possível continuarPasta de Não-FinalizadosArquivo NZB incompleto %sSequência de arquivos multiparte incompletaDescrição de feed RSS incorreta "%s"Parâmetro incorretoValor incorreto para %s: %sSenha %s codificada incorretamenteIndexador id (%s) não foi encontrador para avaliar arquivosIndexaçãoArquivo NZB %s inválido. Pulando (razão=%s, linha=%s)Codificação inválida do modelo de e-mail %sEndereço do servidor inválido.Detalhes inválidos do servidorRegistro inválido de etapa no histórico para %sInverterRecomenda-se que você adicione este local como favorito para acessar o SABnzbd quando ele estiver sendo executado em segundo plano.Tarefa com falhaTarefa concluídaUnir arquivosUnindoManter em pastas separadas os downloads soltosIdiomaÚltimaÚltimos AlertasAbrir navegador ao iniciarAbrir o navegador padrão ao iniciar o SABnzbd.Limitar VelocidadeAtalhosLista todas as extensões indesejadas. Por exemplo: exe ou exe, comLista de extensões de arquivo que devem ser excluídos após o download.
Por exemplo: nfo ou nfo, sfvLista de intervalos de rede localCarregandoFalha ao carregar %sCarga de %s falhou com os seguintes erros: %sEnderaço IPv4 localLocalização do banco de dados de histórico e administrador de fila.
Só pode ser alterado quando a fila estiver vazia.Local dos arquivos de log do SABnzbd.
Será necessário reiniciar o SABnzbd!Local para armazenar downloads concluídos, totalmente processados​​.
Pode ser anulado por categorias definidas pelo usuário.Local para armazenar downloads não processados.
Só pode ser alterado quando a fila estiver vazia.Local onde os arquivos .nzb serão armazenados.Pasta de LogLogsConexão perdida com SABnzbd..BaixaMinúsculasMBTornar Windows compatívelCorrespondidoVelocidade MáxVelocidade máxima da linhaNúmero máximo de tentativas por servidor.Máximo de tentativasSignificadoEspaço livre mínimo para a pasta temporária de downloadsFaltando chave de sessãoArtigos faltandoModeradasegunda-feiraMêsMaisMais votos negativos do que positivosNome FilmeNome.FilmeNome_FilmeMovendoMovendo...Multi-OperaçõesRótulo multi-parteChave NZBNZB adicionado à filaNomeNome do servidor / DNS LookupNomeandoNuncaNova versão %s disponível emNova versão disponívelPróxParâmetros NiceSem acessoNenhum modelo de e-mail encontradoSem pastasSem pós-processamento por causa de falha na verificaçãoNenhum destinário fornecido, e-mail não enviadoSem resultadosNenhum método de autenticação apropriado foi encontradoNenhumNormalNão EncontradoNão disponívelNão há espaço em disco suficiente para completar os downloads!Não utilizadoNada selecionado!Centro de NotificaçõesNotificação Enviada!NotificaçõesNotifyOSDQuantidade de segundos entre as varreduras de arquivos .nzb.Senha OPCIONAL da contaNome de usuário OPCIONAL da contaDesligadoFila antiga detectada, use "Situação -> Reparação da fila" para converter a filaAo ConcluirEm caso de falha, tente um NZB alternativoAo terminar a filaEm que dia do mês ou da semana (1 = segunda-feira) seu provedor de Internet redefine sua quota? (Opcionalmente com hh: mm)Apenas Obter Artigos para o Topo da FilaRealizar pós-processamento apenas em trabalhos que passaram todas as verificações PAR2.Utilize apenas para servidor remoto Growl (host: porta)Apenas utilize esse servidor para essas categorias.Abrir URL InformativaAbra uma janela de terminal e digite a linha (exemplo):Abrir pasta de finalizadosOpcionalNZB Suplementar OpcionalSenha de autenticação opcional.Usuário de autenticação opcional.Senha opcional para o servidor GrowlOpcionalmente, especifique um nome de arquivoOpçõesOu arraste e solte arquivos na janela!OrdemNome do arquivo originalTrabalhos órfãosOutrosOutras MensagensOutro problemaFora da retençãoEM PAUSAValidação de par falhou em %s, enquanto QuickCheck foi completo!Parâmetros:Número do EpisódioSenhaArquivo de senhasSenha mascarada em ******, digite novamentecom senhaCaminhoModeloModelo do padrãoPausarPausar TodosPausar o download durante o pós-processamento.Pausa dePausar por 1 horaPausar por 15 minutosPausar por 3 horasPausar por 30 minutosPausar por 5 minutosPausar por 6 horasPausar por quantos minutos?Pausar por...Pausa tarefas de alta prioridadePausa tarefas de baixa prioridadePausa tarefas de prioridade normalPausar o pós-processamentoPausadoPausar o download no início do pós-processamento e retomar quando concluído.Pausando NZB duplicado "%s"Percentual de velocidade da linhaPermissões para downloads concluídosChave API pessoalChave API pessoal para Prowl (obrigatório)Notas pessoaisEsteja ciente de que o nome de host 0.0.0.0 vai precisar de um endereço IPv6 para acesso externoPor favor insira os detalhes de seu provedor de usenet primário.PortaPorta onde o SABnzbd será ativado.O pós-processamento falhou para %s (%s)Pós-processamentoPós-processar apenas os trabalhos verificadosPós-processamentoPós-processamento iniciadoO pós-processamento foi cancelado (%s)Script de usuário de pré-filaPredefiniçõesAperte a tecla Windows+R e digite a linha (exemplo):AntPrevenir balanceamento de cargaAnteriorPrioridadeProvável compartilhamento de contaProblema comResultado ProcessadoProcessamentoO programa não iniciou!ProgressoProwlEndereço IPv4 públicoEliminarLimpar NZBs TerminadosLimpar NZBs FalhadosLimpar NZBs Falhados & Excluir ArquivosLimpar HistóricoLimpar NZBsLimpar NZBs & Excluir ArquivosLimpar FilaLimpar o Histórico?Limpar a fila?PushbulletPushoverVersão do PythonFilaFila dos primeiros 10 itemsFila concluídaLimite de itens na filaReparação da filaVerificação Rápida...Verificação RápidaSairQuotaQuota restantePeríodo da quotaQuota esgotada, pausando o downloadRRSSIntervalo de verificação de RSSO feed RSS %s estava vazio%s executadoIntervaloOpções raramente utilizadas. Para seu significado e explicação, clique no botão Ajuda para ir para a página Wiki.
Não altere estas sem checar o Wiki em primeiro lugar, já que algumas têm sérios efeitos colaterais.
Os valores padrão estão entre parênteses.Ler Todos os Feeds AgoraLer FeedLer feeds RSSLer todos os feeds RSSLeia a sessão ajuda no Wiki sobre isso!AtualizarTaxa de AtualizaçãoTaxa de atualizaçãoRecusarCaminho base das pastas relativasRestanteRemover NZBRemover NZB & Excluir ArquivosRemover servidorRemover todos os arquivos selecionadosRemover trabalhos encerradosRemover tarefas com falhaA remoção de %s falhouRenomearRepararReparação falhou. Blocos de reparação insuficientes (faltam %s)ReparandoReparação falhou, %sReparando...Repetir testeSubstituir espaços no nome da pastaSubstituir pontos no nome da pastaSubstituir pontos por espaços no nome da pasta.Substituir espaços por sublinhado no nome das pastas.InformarRequerRequer uma conta ProwlNecessária uma conta PushbulletNecessário uma conta PushoverRequiresCatReiniciarRedefinir Quota agoraPrimeiro dia do cicloReiniciarReiniciar SABnzbdReinicie sem loginReiniciando SABnzbd...ResultadoContinuarContinua tarefas de alta prioridadeContinua tarefas de baixa prioridadeContinua tarefas de prioridade normalContinuar o pós-processamentoContinuarTempo de retençãoRepetirAtualizar todosRepetir todosAtualizar todos com falhaAtualizar todos os trabalhos com falhaRepetir todos os trabalhos com falha no Histórico?Repetir todos os trabalhos com falha?Executando scriptExecutando script...Executando script de usuário %sS01E05 Pasta Do EpisódioS01E05 Pasta Da TemporadaSABnzbd %s iniciadoHost do SABnzbdSenha do SABnzbdPorta do SABnzbdAssistente de Início Rápido do SABnzbdUsuário do SABnzbdVersão do SABnzbdServidor Web do SABnzbdSABnzbd detectou um erro fatal:Encerramento do SABnzbd concluídoSABnzbd agora será executado em segundo plano.Servidor SMTPO comando SQL falhou. Consulte o logSSLsábadoGravarSalvar AlteraçõesSalvoFalha ao salvar %sSalvando...Varrer pasta de assistidosAgendamento para um servidor inexistente %sAgendamentoScriptCódigo de saída do script é %sScriptsBuscaNúmero da TemporadaSelecione um idioma para a interface web.Selecione somente se seu provedor permitir conexões SSL.SeleçãoEnviarEnviar GrupoEnviar notificações RSSEnviar de volta para a filaEnviar e-mail quando um feed RSS adicionar tarefas à fila.Enviar e-mail quando o disco estiver cheio e SABnzbd estiver pausado.Enviar comando do grupo antes de solicitar artigos.Enviar notificações ao GrowlEnvia notificações para o Centro de NotificaçõesEnviar as notificações a NotifyOSD.Enviados %s para a filaOrdenação de SériesServidorServidor %s requer usuário/senhaServidor %s usa um certificado HTTPS não confiávelO servidor %s será ignorado por %s minutosDetalhes do ServidorEndereço do servidorEndereço de servidor "%s:%s" não é válido.Endereço do servidor necessárioDescrição do servidorBalanceamento de carga do servidorNome de servidor não encontradoSenha do servidorServidor parou durante a sequência de login.Servidor requer usuário e senha.Erro do servidor (código do servidor %s); não foi possível obter %s de %sServidoresDefinir padrão de permissões para arquivos/pastas concluídos.
Em notação octal. Por exemplo: "755" ou "777"Define o servidor para envio de e-mails.A configuração está completa!O download deve retomar quando a quota for restabelecida?Mostrar TodosMostrar Opções de EdiçãoMostrar FalhadosMostrar LogsNome do ShowPasta do Nome do ShowExibir conexões ativasMostrar detalhesExibir interfaceNome.do.ShowNome_do_ShowMostrando %s a %s de %s resultadosMostrando um resultadoEncerrarDesligar o PCEncerrar o SABnzbdEncerrandoSinal %s encontrado. Salvando e saindo...TamanhoAlguns arquivos falharam na verificação de "%s"Alguns servidores fornecem um NZB alternativo quando um download falha.Perdão, não conseguimos interpretar isso. Tente novamente.OrdenarString de ordenaçãoOrdernar por IdadeOrdenar por Idade (Mais novo→Mais antigo)Ordenar por Idade (Mais antigo→Mais novo)Ordenar por Idade Mais novo→Mais antigoOrdenar por Idade Mais antigo→Mais novoOrdenar por Nome (A→Z)Ordenar por Nome (Z→A)Ordenar por Nome A→ZOrdenar por Nome Z→AOrdenar por Tamanho (Maior→Menor)Ordenar por Tamanho (Menor→Maior)Ordenar por Tamanho Maior→MenorOrdenar por Tamanho Menor→MaiorOrdenaçãoCódigo fonteSpamEspecialVelocidadeLimite de velocidadeLimite de velocidadePC em esperaIniciar o AssistenteIniciando reparaçãoInicialização/EncerramentoSituaçãoEstado e opções de interfacePararParando...AssuntoEnviarEnviado. Obrigado!domingoErro suspeito no downloaderOpçõesCarga do sistemaPastas de SistemaPerformance do Sistema (Pystone)TEXTOMUITO GRANDETarefaPasta temporáriaPasta Temporária de DownloadsTestar E-mailNotificação de testeTestar ServidorTestando detalhes do servidor...O botão "Reparar" irá reiniciar o SABnzbd e fazer uma reconstrução
completa do conteúdo da fila, preservando arquivos já baixados.
Isto modificará a ordem da fila.A ferramenta de download automático da usenetA caixa de seleção ao lado do nome do feed deve ser assinalada para que o feed seja ativado e automaticamente verificado por novos itens.
Quando um feed é adicionado, ele só vai pegar novos itens e não algo que já esteja no feed RSS a menos que você pressione "Forçar Download".O nome do host não foi definido.O número de conexões permitidas por seu provedorO servidor não respondeu propriamente a chamada de reconhecimentoNão há conexões definidas. Por favor, defina pelo menos uma conexão.Existem tarefas órfãs na pasta de downloads.
Você pode optar por excluí-las (incluindo arquivos) ou enviá-las de volta para a fila.Esta chave permitirá que programas de terceiros adicionem NZBs ao SABnzbd.Esta chave dará a programas de terceiros pleno acesso ao SABnzbd.Este mêsEste servidor não permite SSL nesta portaEsta semanaIsso irá impedir que o conteúdo seja atualizado quando o cursor do mouse estiver sobre a fila.Isto irá reiniciar o SABnzbd.
Use-o quando você achar que o programa tem um problema de estabilidade.
Os downloads serão pausados antes de reiniciar e retomados depois.Isto irá enviar um e-mail de teste para sua conta.quinta-feiraTempo esgotadoTempo esgotado: Tente habilitar o SSL ou conectar em uma porta diferente.Tempo restanteTempo limiteTí­tuloPalavras chave do títuloPara: %s De: %s Data: %s Assunto: SABnzbd informa Disco Cheio Olá, SABnzbd parou de baixar porque o disco está quase cheio. Por favor, arrume espaço e continue SABnzbd manualmente. HojeAlternar Adição de NZBMuito pouco espaço em disco. Forçando PAUSEExcesso de conexões ao servidor %sExcesso de conexões, por favor pause o download ou tente novamente mais tardeTopoMenu SuperiorTotalResolução de problemasTeste a nossa nova skin Glitter! Novo design otimizado para desktop e aparelhos móveis. Vá em Configurações -> Geral para mudar a sua skinTentar prever a conclusão bem sucedida de um futuro download? (lento!)Testando 7zip com a senha "%s"Tentando verificação SFVTentando obter NZB de %sTentando definir o status do servidor inexistente %sTentando descompactar com a senha "%s"terça-feiraAjustes finosTipoUO caminho UNC "%s" não é permitido aquiINDESEJADOA busca da URL falhou; %sURLGRABBER PAROU DE FUNCIONARAcesso não autorizadoDesbloquearServidor não definido!Erro desconhecido ao decodificar %sAção desconhecida: %sFalha de autenticação desconhecida no servidor de e-mailDescompactarDescompacta os arquivos (rar, zip, 7z) dentro de arquivos.Aninhamento de descompactação com muitos níveis [%s]Descompactados %s arquivos/pastas em %sDescompactandoA descompactação falhou. %sA descompactação falhou. Erro de CRCA descompactação falhou. O arquivo exige uma senhaDescompactação falhou, o caminho é muito extensoA descompactação falhou. Veja o logA descompactação falhou. Não foi possível encontrar %sA descompactação falhou. Erro de escrita ou disco cheio?Arquivo NZB inutilizávelArquivo RAR inutilizávelA extensão indesejada está no arquivo rar %sExtensões indesejadasPara cimaAtualização Disponível!EnviarEnviar NZBEnviar: .nzb .rar .zip .gz, .bz2Tempo ativoUsar configurações globais de interfaceUsar nomes temporários durante o pós-processamento. Desative quando seu sistema não lidar com isso corretamente.Utilizado antes de um NZB entrar na fila.Cache utilizadoÚtil se um newsserver tem mais de um endereço IPv4/IPv6Usar PastasChave do usuárioChave do usuário (obrigatório)O script do usuário pode marcar um trabalho como falhoUsuárioValoresVerificado com sucesso. Usando arquivos SFV.VerificandoVerificando...VersãoMuito BaixaVídeoPontuação do vídeoExibir Log do ScriptVirus/spamEspere %s segundo(s)AVISO:ATENÇÃO: Tarefa "%s" interrompida em razão de pontuação (%s)ATENÇÃO: Extensão indesejada no arquivo RAR em "%s". O arquivo não desejado é %s ATENÇÃO: Tarefa "%s" em pausa em razão de pontuação (%s)AguardandoAlertaAtenção: LOCALHOST é ambíguo, use endereço IP numérico.AlertasPasta de AssistidosVelocidade de Varredura na Pasta de AssistidosInterface Webquarta-feiraChecar semanalmente por nova versão do SABnzbd.QuandoQuando durante o download ficar claro que muitos dados estão faltando, cancela a tarefaQuando um script do usuário retornar um código de saída diferente de zero, o trabalho será marcado como falhoQual percentual de velocidade da linha o SABnzbd deve utilizar, por exemplo, 50Quem devemos dizer que enviou o e-mail?WikiNotificações WindowsVelocidade de escritaXAnoPastas Ano-MêsVocê deve habilitar o JavaScript para Plush funcionar!Você deve definir a largura de banda máxima antes de definir um limite de bandaSua versão UNRAR é %s, nós recomendamos a versão %s ou superior.
Chave Pushbullet API pessoal (necessária)[%s] Erro "%s" na união de arquivos[%s] Erro "%s" ao descompactar os arquivos RAR[%s] Unidos %s arquivos[%s] Nenhum conjunto par2[%s] PAR2 recebeu opções incorretas. Verifique em Configuração->Opções[%s] Verificação Rápida OK[%s] Reparado em %s[%s] Verificado em %s. Todos os arquivos corretos[%s] Verificado em %s. É necessário repararmódulo _yenc... NÃO encontrado!artigosáudioajuste de maiúsculaslimparddiadiasdesativar o servidorvotos negativos recebidoativar o servidorarquivohhorahoraspalavras chaverestantesmmanualminmin.minnão instaladodedesligadoligadoouou menospáginaaplicativo par2... NÃO encontrado!protegido por senhasegsegundosveja o arquivo de logspamtextodesconhecidoaplicativo unrar... NÃO encontrado!aplicativo unzip... NÃO encontrado!vídeosemanaSABnzbd-2.3.2/locale/ro/LC_MESSAGES/SABnzbd.mo0000644000000000000000000022660213217005256016424 0ustar 00000000000000 d @o@dAB |CD}EgF*~F'FFFG G?GNGnG GGGPHXH_HgHoHwH1HHH*HIA'IiI?I.J2JBJJJRZJ[J KK!K#*KNKkK#K$KK KK.K:L'WL'LLLLLL L L LL MM#M''MJOMM/MMMM N(N):N*dN N NNNNNN N/Nh"O OO*PFPHPMP%TP#zPPP PPPQ QQQQQ QQ R/RJRhR!R6R-R"S1S@S"^S6SS SS.S'T ?TIT_TuTS~TT TTU U.U"HU8kUUUUUU UVV !V -V;VUV mV#wVVV VV*V W6 WWWiWpW rW|W W3W W W W WWWXX*X.X 5X@X QX_X(uXX X-X YY#9Y]Y&dY Y)YYY4YZ?Z^ZxZZ ZZ,Z,Z1,[5^[[[[ [[['[\5(\ ^\'i\ \ \ \ \\ \ \\ \\]]7]O]S]X] i]w]$}]] ] ]]#]^ ^ ^&^8^S^ Z^f^z^ ^ ^^^^^_$_<_ N_[_4x__S_`1`I`d`Hl` ` `` ` ``(`.$a)Sa&}a,a<a&b5bPb'cbbbbb b c&!c-Hcvccc ccc c cdd0dEd Xdfdodvddd%d!de+#e Oepe!e*e!ee'f7f*Rf"}ff#ff!fg9gRgpggg ggggghhh2hKhfhAuhh'h!hi8iKiTi]i-dii/igi 0j}G}!a}!}"}}}%}~~ ,~:~@~ O~]~n~u~4~ ~ ~~ ~*~ !& .: @(J s} 2Je{MЀ#(%9_Rn<""EUuj(>-Fty ȃ ك06K ] ~  Є  . ?L[jo u ʅ߆  : B O\c  ʇ -;B2I | ш)0GNWp  ̉։މ!(B[w ъ!  /AXn  ܋0.J y ƌ׌# #*,Anv } 4  3%3Y.)؎"3B I-j(Џ$ߏ/Eb"r&:o)o3 "3 KX g q"{ ƒ ג' (>;.z /Ɠ/-&-T&&$Д$33N11    *7GX_| Ֆޖ /!Q Vb | "p25AX>ݚ= Z+e W,Ŝ Μ>؜ (.="!)AK E7}.П'.35T]u֠-/Nk -ơ"#1.U$͢  )3:bX$ : &3<P#_"% ܤ   ' 2>0GEx/:9BQ k y%RUMW=0!6; Q_af1yEB+4#`)éJթ 4&H'o Ϫժת۪  "')049 >LOSVYaf  ϫ " ȱԲٳ,($Mmɴ%ܴ" %/F  $ / 9FLfŶ0ֶ(N0N \e ~fuz *׹)">ajy;F,22env ˻ݻ .HA2#Լ 72L2 ½̽  = ^2ɿ*ٿ(-M j"u D _"i&' &%"L@o7# +:If! 6.L!\~ \!@H4^(F "- <J fp   "3 GQ*d? 8'` q     0:(k&3" *, W*b -! =4M<"% .%><dA 0=P6 %  # 0 >LS cm u# &>%Dj{ . & 4?Pi}  +E[l3x!Tv"K  $ 2 >J%Q7w&/5F<.."'Jj 03 6Vimu  #(-Vn%4%/ !<'^/='44 i1& .3%N't($! 2A[y ~  :!N'p#" 0P-W{  %"=D` $ ! , :F M Zf5,0A Y ep w$ 2Pbu$|E:" *4 EQU7]\/2MbQF 3( "3V i@4+(Tm' Vh|8">S gNqx9 R_*{jOSx- ; H V b"n  $ 88F%  ( @Jbg !   7&*^7 G +?&T { 5[ W$d#e#,7NdB6-6E$| !' '0X$a  E U `mu;  1'6Lez,++Gs Y )*T-ioKb&g)*'A ) 4> U _j /-Jx" !<Oiy) /:Ca $# ,MT dp#% 6CCK   ,+6%2\     " .:Nl&$% +8K^$y.% .BUgv !$ 4 U(a   * )5%<Gb  "= * 4  < I a ;{ A 2 , )F $p    ( 3 * I X %g    &  ) .0 D_  { 2( [ +{       (7 I U1a   #3:;Gv HHAFF..G,v,FFD^D  3=Qbu{ +  *8W \8f  ,  *(G=pNLC )*TYi2\ 3 ?MSk+/'C#kg  V+G ^1 # 3I [h,z: A 3L (   # 3 ,)!$V!({!6!!!."C"U"Y" s" }"#" ""+"w"0u# #F## $$;$0L$+}$$$&$ $ $%%% %%2% E%P% b%9l%S%>% 9& G&AS& &&!&&&0&!'d''|'e (Do(.(-())*)=)?)B)BQ)Y)P)+?*.k*9***S+U+o+4+)+++, ,#,+,-,0,5, J,V,h,p,r,w, {,,,,,,, ,, ,,,,,,,- --'-,- 1-<-U-n- t- SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!
If authentication is enabled, you will need to login again.NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Also test releasesAlwaysApplication TokenApplication token (required)Apply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentCompact layoutComplete FolderComplete folder speedCompletedCompleted Download FolderConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDisable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDualView1DualView2E.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable notification scriptEnable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExecutes a custom scriptExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra history columnExtra queue columnExtracting...FILTEREDFailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send Windows notificationFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File not on serverFile setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.ForceForce DisconnectForce DownloadForcing disconnectFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGo to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHelpHibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIndexer id (%s) not found for ratings fileIndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIssuesIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job failedJob finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!Location for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLog inLog outLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMeaningMinimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateMondayMonthMoreMore thumbs down than upMovie NameMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelNZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNone of the enabled servers have the 'Default' category selected. Jobs in the queue that are not assigned to one of the server's categories will not be downloaded.NormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification ScriptNotification Sent!Notification script "%s" does not existNotificationsNotifyOSDNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly external access requires loginOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPROPAGATING %s minPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.Pre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressPropagation delayProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemember meRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRemoving jobRemoving jobsRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...ResultResumeResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScript returned exit code %s and output "%s"ScriptsSearchSeason NumberSelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...SubjectSubmitSubmitted. Thank you!SundaySuspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETabbed layout
(separate queue and history)TaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUnauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UploadingUptimeUse global interface settingsUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User logged inUser logged in to the web interfaceUser script can flag job as failedUsernameValuesVerified successfully using SFV filesVerifyingVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen the user script returns a non-zero exit code, the job will be flagged as failed.When your IP address changes or SABnzbd is restarted the session will expire.Which percentage of the linespeed should SABnzbd use, e.g. 50Which script should we execute for notification?Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2016-07-29 16:20+0000 Last-Translator: nicusor Language-Team: Romanian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:31+0000 X-Generator: Launchpad (build 18511) SABnzbd nu poate găsi fişierele de la interfaţa-web %s.
Vă rugăm să reinstalaţi programul din nou.

SABnzbd a detectat informaţii salvate de la o altă versiune SABnzbd
dar nu poate să refolosească informaţiile de la cealaltă versiune de program.

Ar fi bine să terminaţi coada mai întâi cu cealaltă versiune de program.

După aceia , porniţi programul cu opţiunea "--clean".
Aceasta va şterge coada curentă şi istoricul!
SABnzbd citeşte fişierul "%s". SABnzbd a detectat că fişierul sqlite3.dll lipseşte.

Unele antivirusuri şterg acest fişier.
Vă rugăm să verificaţi antivirusul , încercaţi să reinstalaţi SABnzbd şi plângeţivă autorului antivirusului.

SABnzbd are nevoie de un tcp/ip port liber pentru serverul său intern.
Portul %s de pe %s a fost încercat , dar nu este disponibil.
Alt program foloseşte portul sau SABnzbd este deja pornit.

Vă rugăm să reporniţi SABnzbd cu un număr de port diferit. SABnzbd are nevoie de o adresă gazdă validă pentru serverul său intern.
Dvs. a-ţi specificat o adresă invalidă.
Valori sigure sunt localhost şi 0.0.0.0

Vă rugăm să reporniţi SABnzbd cu o adresă gazdă bună. SABnzbd vine cu ABSOLUT NICI O GARANŢIE. Acesta este software gratis, şi sunteţi binevenit să-l redistribuiţi în anumite condiţii. Este licenţiat sub GNU General Public License versiunea 2 sau (la opţiunea dumneavoastră) orice versiune ulterioară. %s -> Codificare Necunoscută%s => lipsă de pe toate serverele, ignorare%s articolele au avut duplicate diferite%s articolele au fost incorecte%s articolele au fost lipsăArticolele %s au fost eliminatedosarul %s: eroare accesare %s%s fişiere în %s%s nu este o valoare octală corectă%s nu este o adresă email validă%s lipsă Reolvare adresă 
Închidere SABnzbd terminată.
Aşteptaţi timp de aproximativ 5 secunde şi apoi faceţi clic pe butonul de mai jos.

Reîmprospătează
+ Depanare+ Info+Ştergere+Reparare+DezarhivareDosar Copie de Siguranţă .nzb0 este prioritatea cea mai ridicată, 100 este prioritatea cea mai scăzută1x05 Dosar Episod1x05 Dosar SezonSetul 7ZIP "%s" este incomplet, nu pot dezarhivaFişier executabil 7za ... Indisponibil!
Dacă este activată autentificarea v-a trebuie să vă logați din nou.NOTĂ:Dosarele vor fi create automat când se Salvează. Puteţi utiliza căi absolute pentru a salva în afara dosarelor implicite.Informaţiile vor nu vor fi mutate. Necesită repornire SABnzbd!VârstăAPI (fără Configurare)Cheie APICheie API sau Cod QRCheie API incorectă, Folosiţi cheia api din Configurare->General în programul dumneavoastră terţ:Cheie API lipsă, vă rugăm să introduceţi cheia api de la Configurare->General în programul dumneavoastră terţCheie API pentru ProwlRenunțăRenunță DacăAnulează sarcini care nu pot fi terminateAnulat nu poate fi finalizatTerminat, encriptare detectatăAbandonat, filtru de rating potrivit (%s)Oprit, extensii nedorite detectateAcceptăAcces interzisAcțiuneAcțiune când se descarcă în baza de reguli de filtrare.Acțiune când se detectează extensie nedorită într-un fișier RARAcțiuni când se descarcă un RAR encriptatAcțiune când se detectează o extensie nedorităAcțiuniAdaugăAdaugă fişierAdaugă NZBAdaugă fișiere NZB Adaugă PlanificareAdaugă ServerNZB-uri AdăugateDosar AdministrativCategorii AfectateVârstaToateToate fișierele merg într-un singur directorToate rețelele locale încep cu acest prefixe (de regulă "192.168.1.")Permite load-balancingPermite load-balancing cu o optimizare pentru IPv6Testeaza şi versiuni de încercareÎntotdeaunaToken de AplicațieToken de Aplicație (necesar)Aplică la SelecţieSunteţi sigur că doriţi să reporniţi SABnzbd?Sunteţi sigur că doriţi să inchideţi SABnzbd?Sunteţi sigur?ArgumenteLimită Cache ArticoleIdentificator ArticolCel puținCel multAudioRating AudioAutentificare nereuşită, verifică nume utilizator/parolă.Autentificare lipsă, vă rugăm să introduceţi numele de utilizator/parola de la Configurare->General în programul dumneavoastră terţ:Auto repornireAuto-pauză când spaţiul liber este sub această valoare.
În octeţi, urmaţi opţional de K, M, G, T. De exemplu: "800M" sau "8G"Sortează automat obiectele dupa vârstă (medie).BÎnapoiServer SecundarRăspuns greșit de la Pushbullet (%s): %sRăspuns greșit de la Pushover (%s): %sProgramator Greşit %s la %s:%sArticoul yEnc invalid în %sDescărcatBlochează Reîmprospătarea HoverCoadăRăsfoireModel CPUStochează articolele în memorie pentru a reduce acesul disc.
În octeţi, opţional urmaţi de K,M,G. De exemplu : "64M" sau"128M"Articole %s în cache (%s)AnuleazăNu pot schimba permisiunile lui %sNu mă pot conecta la serverul %s [%s]Nu pot crea %s dosar %sNu pot crea copie de rezervă pentru %sNu pot crea dosarul %sNu pot crea dosar final %sNu pot crea fişier temporar pentru %sNu pot gasi şabloane email în %sNu se poate găsi şablon web:%s, se încearcă şablon standardNu pot porni navigatorul web, probabil nu a fost găsitNu pot contacta serviciul SABHelperNu pot citi %sNu pot citi Dosar Urnărire %sNu pot trimite, informații necesare lipsăNu pot scrie în baza de date ISTORIC, verificaţi permisiunile de acces.Nu pot scrie în fişierul INI %sCategoriiCategorieModificările nu au fost salvate, şi vor fi pierdute.Modificările vor necesita repornirea SABnzbd!Selectează totVerifică înainte de descărcareVerifică Versiuni NoiSe verificăInterval verificare (în minute, cel puţin 15). Inactiv când se foloseşte Planificatorul!Alege o temă.Listă CurăţenieŞtergerea lui %s nereuşită.ŞtergeResetează StatisticiClick pe butonul de Repetare test pentru a determinaClic pentru a testa detaliile introduse.Închidere a oricărei ferestrele browser/file NU va închide SABnzbd.Listă separată prin virgulăComentariuAspect compactDosar CompletVitează completă directorFinalizatDosar Descărcări FinalizateConfigurareFişier ConfigurareConfigurareConfirmă Ştergere IstoricConfirmă Ştergere CoadăConfirmatConectare %s@%s eșuată, mesaj=%sConexiune Reuşită!Conectare eșuată!ConexiuniLăţime ContainerNu pot determina reultatul conexiunii (%s)Nu pot dezarahiva %sNu am putut scrie. Verifică dacă director poate fi modificat.Planificări CurentePersonalizatDDUPLICATZilnicDosare ZilniceBază de date Istoric coruptă, creat un nou fişier golPanou de ControlSortare DatăFormat datăZi din lunăDeceniuDecodarea %s nereuşităImplicitDosar de Bază ImplicitŞtergeŞtergeȘterge totŞtergere FinalizatăŞterge NereuşiteŞterge după descărcareŞtergeţi toate obiectele complete din Istoric?Ştergeţi toate fişierele descărcate?Ştergeţi toate obiectele din coadă?Ştergeţi toate fişierele nereuşite din istoric?Ştergere %s nereuşită!Detectează Descărcări DuplicateDetectează episoade duplicate în serialeDispozitivDispozitiv la care să se trimită mesajulDispozitiv(e)Dispozitiv(e) la care să se trimită mesajulDezactivează gestionarea cotelorDezactivatDezactivează HTTPS din cauza lipsei fişierelor CERT şi KEYIgnorăDeconectează de la serverul(ele) Usenet când coada e goală sau în pauză.Deconectează când Coada e GoalăNotificări Disc PlinEroare disc la crearea fişierului %sDisc plinDisc plin! Pauză ForţatăFă o verificare extra bazată pe fişiere SFVAutentificare invalida pentru flux %sCota se resetează în fiecare zi, săptămână sau lună ?Nu aveţi un furnizor usenet? Vă recomandăm să încercaţi %s.JosDescarcăDescărcare terminatăDosar DescărcareDescărcarea a eșuatDescarcă toate fișierele par2Descărcare euată, - Nu este pe serverul(ele) dumneavoastrăViteză de descărcare directorDescărcarea ar putea eşua, doar %s din %s disponibilDescărcateDescărcat în %s cu o medie de %sB/sDescărcareDescărcăriVedereDuală1VedereDuală2De ex.De ex. 8 sau 20ENCRIPTATEROARE:EROARE: %sEROARE: CRC nereuşit în "%s"EROARE: calea este prea lungă (%s)EROARE: nu pot găsi "%s"EROARE: eroare scriere (%s)Timp EstimatEditeazăEditează Detalii NZBAltfel Întrerupe DacăEmailNotificări Email Sarcină TerminatăDestinatar EmailExpeditor EmailEmail Trimis!Dosar Şabloane EmailAdresă de email către care se trimite email.Email reuşitUrgențăGolFişier NZB gol %sValoare RSS gasită a fost goală (%s)ActiveazăActivează 7zipActivează Sortare DatăActivează FiltrareActivează GrowlActivează HTTPSActivează Sortare FilmeActivează NotifyOSDActivează notificări ProwlActivează notificare PushbulletActivează notificări PushoverActivează verficări SFVActivează Sortare TVActivează UnzipActivează notificări WindowsPermite acesarea interfeţei de la o adresă HTTPS.Activează redenumire dosarActivează pentru folosire de memorie mai puţină. Dezactivaţi pentru a preveni ca sarcinile lente să blocheze coada.Activează scriptul de notificareActivează gestionarea cotelorActivează dezarhivarea recursivăActivatFinalizarea unei căi cu un asterix * va preveni crearea de dosare sarcini.Introdu URLNume EpisodNumăr EpisodNume.EpisodNume_EpisodEroareEroare "%s" în timpul file_join a %sEroare "%s" în timpul rulării par2_repair pe setul %sEroare "%s" în timpul rar_unpack a %sEroare "%s" în timpul rulării unzip() pe %sEroare %s în timpul rulării par2_repair pe setul %sEroare %s: Trebuie să furnizaţi un nume utilizator şi parolă validEroare la crearea cheiei şi certificatlui SSLEroare obţinere info TV (%s)Eroare importare %sEroare încărcare %s, fişier corupt detectatEroare ştergere %sEroare ştergere dosar curent (%s)Eroare redenumire "%s" în "%s"Eroare adăugare %s, ştergemEroare la oprirea sistemuluiDoar-eroriEroare: Lungimea cale ar trebuie să fie sub %s.Eroare: Coada nu este goală, nu pot schimba dosar.Eroare: Cheie Sesiune IncorectăEroare: Cheie Sesiune NecesarăErori/AvertismenteTotExempluExecută script personalizatÎnchide SABnzbdExtensieAcces extern la internetParametri Extra PAR2Coloană extra de istoricColoană extra la CoadăDezarhivare...FLTRATNereuşitAutentificare nereuşită la serverul %sFacere nereuşită (%s)Mutare %s în %s nereuşităAutentificare server mail nereuşităÎnchidere bază de date nereuşită, vedeţi jurnalÎnchidere conexiune mail nereuşităCompilarea unei căutări regex nereuşită: %sConectare server mail nereuşităPunere sistem în hibernare nereuşităImportare %s a fişierelor de la %s nereuşităNu am putu inițializa %s@%s din cauza următorului motiv: %sIniţializare conexiune TLS nereuşităNu am putu muta fişierRedenumire fişiere similare : %s în %s nereuşităRedenumire:%s în %s nereuşităNu am putut reporni NZB după pre-verificare (%s)Descărcare %s: %s din RSS nereuşităNu am putu trimite mesajul ProwlNu am putut trimite notificări în FereastrăTrimitere email nereuşiăNu am putu trimite mesajul pushbulletNu am putut trimite mesajul de pushoverPunere sistem în aşteptare nereuşităPornirea interfeţei-web nereuşităNu am putu porni interfața web: NereuşitEroare în tempfile.mkstempEroare fatalăEroare fatală la salvareEroare fatală în AssemblerFluxDescarcăDescarcă NZB din URLDescărcareDescărcare %s blocuri...Descărcare blocuri extra...Fişierul %s este gol , ignorămExtensie fișierFişier ce conţine parole pentru fişiere RAR encriptate.Unirea fişierului %s nereuşităNume fişier sau cale Certificat HTTPS.Nume fişier sau cale cheie HTTPS.Nume fişier sau cale Cheie HTTPS.Fișierul nu este pe serverSet fişiereNume de fișierFiltruIgnoră fişiere monstră (de ex. monstre video)PrimulDosar ce conţine şabloane email utilizator.Dosar pentru supraveghere fişiere .nzb.
Scanează de asemenea şi arhivele .zip .rar .tar.gz de fişiere .nzb.Dosar/CaleDirectoarePentru email autentificat, nume cont.Pentru email autentificat, parola.Pentru servere: asigurați-vă că numele sun comparibile cu WindowsForțeazăForţează DeconectareaDescărcare ForţatăForțează deconectareaFormate: .nzb, .rar, .zip, .gz, .bz2ForumGol (Temp)Spațiu liberFrecvenţăVineriDe la SxxEyyAPI CompletInterfață Web completăAjutor suplimentar poate fi găsit pe pagina noastrăGBGeneralGenerează o Cheie NouăDu-te la SABnzbdDute la vrăjitorGrowlPorturile HTTP și HTTPS nu pot fi aceleașiCertificat HTTPSCertificate Cheie HTTPSCheie HTTPSPort HTTPSAjutorHibernare PCAscunde Opţiuni EditareAscunde detaliileAscunde/arată fișierele finalizateRidicatăIstoricIstoric Ultimele 10 ObiecteLimită maximă la IstoricȚine-ți tasta shift pentru a selecta un intervalPagina de pornirePagină de pornireGazdăNume Gazdă unde SABnzbd va asculta.Cât timp sau până când doriți să întrerupeți? (în Engleză!)Cât de mult poate fi descărcat în acestă lună (K/M/G)INACTIVINCOMPLETParametri IONiceAdresa IPv6IRCInactivDacă e gol, portul standard va asculta doar în HTTPS.Dacă primiţi acest mesaj de eroare din nou, vă rugăm să încercaţi un alt număr.
Ignoră MonstreIgnoră orice director din interiorul arhivelorIgnorăm duplicat NZB "%s"ÎnÎn cazul "Întrerupere", dumneavoastră trebuie să introduceți parola și să reluați sarcina.În cazul repornirii SABnzbd acest ecran va dispărea în mod automat!În dosarePentru a descărca de pe usenet veţi avea nevoie de un furnizor. ISP-ul dvs. vă poate oferi acces, totuşi un furnizor premium e recomandat.Fulx RSS incompatibilFişier coadă găsit incompatibil, nu pot înaintaDosar IncompletFişier NZB incomplet %sSecvenţă incompletă de unire fişiereDescriere flux RSS incorectă "%s"Parametru IncorectValoare incorectă pentru %s: %sParolă %s codificată greşitId-ul indexului (%s) nu a fost găsit pentru fișierul de ratingIndexareFişier NZB invalid %s, ignorăm (motiv=%s, line=%s)Codificare invalidă a şablonului email %sAdresă server invalidăDetalii server invalideJurnal istoric stagii invalid pentru %sInverseazăProblemeEste recomandat să faceţi clic dreapta şi să faceţi o scurtatură , pe care să o folosiţi pentru a accesa SABnzbd când rulează în fundal.Sarcină eșuatăSarcină terminatăUneşte fişiereleUnimPăstrează descărcările suplimentare în dosare extraLimbăUltimulUltimele AvertizăriPorneşte Navigator Web la PornirePorneşte navigatorul web implicit când se porneşte SABnzbd.Limitare de VitezăLegăturiListă cu toate extensiile nedorite. De exemplu: exe or exe, comListă de extensii fișiere ce trebuie să fie șterse după descărcare.
De exemplu: nfo or nfo, sfvListă de rețele localeSe încarcăÎncărcarea %s nereuşităÎncărcarea lui %s a eșuat cu eroarea %sAdresa IPv4 localăStocarea locală (module cookie) sunt dezactivate în browserul dumneavoastră, setările de interfață vor fi pierdute la încridegea browserului!Locaţia coadei admin şi istoricul bazei de date.
Poate fi folosit doar când coada e goală.Locaţie a fişierelor jurnal ale SABnzbd.
Necesită repornire SABnzbd!Locație pentru stocare , a descărcărilor procesate complet.
Poate fi suprascris de categoriile definite de utilizator.Locaţie de stocare a descărcărilor neprelucrate.
Poate fi schimbată doar atunci când coada este goală.Locaţie unde fişierele .nzb vor fi stocate.Dosar JurnalAutentificareDeconectareJurnalizareAm pierdut conexiunea cu SABnzbd..ScăzutăLitere MiciMBFă Windows compatibilPotriviteViteză MaximăViteză maximă a conexiuniiNumăr Maxim reîncercări pe serverNumăr Maxim reîncercăriSemnificaţieMinim de Spaţiu Liber pentru Dosar Descărcare TemporarCheie Sesiune lipsăArticole lipsăModeratLuniLunăMai multMai multe voturi pozitive ca negativeNume FilmNume.FilmNume_FilmMutareMutare...Operaţii-MultipleEtichetă Multi-părţiCheie NZBNZB adăugat în coadăNumeServer de nume/Căutare DNSRedenumireNiciodatăVersiune nouă %s disponibilă laVersiune nouă disponibilăUrmătorulParametri NiceFără accesŞabloane email negăsiteFără dosareNici o post-procesare din cauza verificării nereuşiteDestinatar necunoscut, niciun email trimisFără rezultateNu am găsit nici o metodă potrivită de autentificareNiciunulNici unul din serverele activate au categoria 'Default' delectată. Sarcinile din coada de descărcare care nu au desemnate o categorie corespunzătoare serverelor nu vor fi descărcate.NormalNepotrivitIndisponibilSpaţiul liber insuficient pe disc pentru finalizarea descărcărilor !NeutilizatNimic selectat!Centru NotificăriScipt de NotificareNotificare Trimisă!Scriptul de notificare "%s" nu existăNotificăriNotificăOSDNumărul de secunde între scanarea de fişiere .nzb.Parolă Cont OPŢIONALNume Cont OPŢIONALOpritCoadă de descărcare veche detectată, utilizează Stare->Reparare pentru a converti coadaLa TerminareLa eroare, încearcă NZB alternativLa terminarea coadei de descărcareÎn ce zi a lunii sau săptămână (1=Luni) ISP dumneavoastră resetează cota? (Opțional cu hh:mm)Ia Articole doar din Vârful CoadeiDoar accesul extern necesităr autentificareExecută post-procesarea doar dacă sarcina a trecut toate verificările PAR2.Foloseşte doar pentru server Growl de la distanţă (gazdă:port)Utilizează acest server doar pentru aceste categorii.Dechide URL InformaţiiDeschide fereastra Terminal şi scrie linia (exemplu):Deschide dosar descărcări completeOpţionalNZB Suplimentar OpţionalParolă autentificare opţionalăNume Utilizator autentificare opţionalParolă opţională server GrowlOpţional specifică un nume de fişierOpțiuniSau trage fișierele în fereastră!OrdineNume de Fişier OriginalSarcini orfaneAlteleAlte MesajeAltă problemăDincolo de retențieÎNTRERUPTSE PROPAGHEAZĂ %s minVerificarea Par eșuată pentru %s, dar VerificareaRapidă reușită!ParametriiNumăr ParteParolăFișier paroleParolă ascunsă în ******, Vă rugăm să re-introduceţiParolatCaleȘablonModel CheiePauzăPauză ToateÎntrerupe Descărcarea în Timpul Post-ProcesarePauză timp dePauză timp de o orăPauză timp de 15 minutePauză timp de 3 orePauză timp de 30 minutePauză timp de 5 minutePauză timp de 6 orePauză pentru câte minute?Pauză timp de...Întrerupe sarcinile cu prioritate ridicatăÎntrerupte sarcinile cu prioritate redusăÎntrerupe sarcinile cu prioritate normalăPauză post-procesareÎntreruptÎntrerupe descărcare la începerea post procesării şi reporneşte când e terminată.Întrerupem duplicat NZB "%s"Procent din viteza conexiuniiPermisiuni pentru descărcări finalizateCheie API personalăCheie API personală pentru Prowl (necesară)Note personaleVă rugăm să fiţi conştienţi că numele gazdei 0.0.0.0 va avea nevoie de o adresa IPv6 pentru acces externVă rugăm să introduceţi detaliile furnizorului dvs principal de usenet.PortPortul pe care SABnzbd îl va asculta.Post Procesare Nereuşită pentru %s (%s)Post procesarePost-Procesează Doar Sarcinile VerificatePost-procesarePost-procesare pornităPost-Procesarea a fost abandonată (%s)Articolele vor fi întrerupte până ce vor avea cel puțin vechimea aceasta. Dacă setați prioritatea descărcării ca Forțat evitați această întârziere.Script utilizator Pre-CoadăPresetăriApasă Start+R şi scrie linia (exemplu):PrecedentPrevine load-balancingPrecedentPrioritatePartajare cont probabilăProblemă cuRezultat ProcesatÎn curs de procesareAplicaţia nu a pornit!ProgresÎntârziere de propagareProwlAdresa IPv4 publicăȘtergeŞterge NZB-uri CompleteŞterge NZB-uri nereuşiteŞterge NZB-uri Nereuşite & Fişiere ŞterseŞterge IstoriculŞterge NZB-uriŞterge NZB-uri & Fişiere ŞterseGoleşte CoadăGoliţi Istoricul?Goliţi Coada?PushbulletPushoverVersiune PythonCoadăPune la Coadă Primele 10 ObiecteCoadă finalizatăLimită maximă la coadăCoadă reparareVerificare Rapidă...Verificare RapidăIeșireCotăCotă rămasăPerioadă CotăCotă epuizată, întrerupem descărcareaRRSSInterval Verficare RSSFluxul RSS %s a fost golDurată %sIntervalOpţiuni folosite rar. Pentru explicaţiile şi semnificaţia lor, click pe meniul Ajutor şi vizitează pagina Wiki.
Nu modificaţi aceste setări fără a verifica mai întâi pagina Wiki , pentru că unele pot cauza probleme serioase .
Valorile originale sunt în paranteze .Citeşte Toate Fluxurile AcumCiteşte FluxCiteşte fluxuri RSSCitește toate feed-urile RSSCiteşte Ajutorul Wiki despre asta !ReîmprospăteazăRata de ReîmprospătareRată actualizareRespingeDosarele relative se bazează peRămasȚine-mă minteŞterge NZBŞterge NZB & Fişiere ŞterseŞterge ServerElimină toate fișierele selectateElimină sarcinile finalizateElimină sarcini nereuşiteŞtergerea %s nereuşităElimin sarcinaElimin sarcinileRedenumeșteReparăReparare nereuşită, blocuri reparare insuficiente (%s mai puţin)Se reparăReparare nereuşită, %sReparare...Repetă testÎnlocuieşte Spaţiile din Numele DosarelorÎnlocuieşte punctele din Numele DosarelorÎnlocuieşte puntele cu spaţii în numele dosarelor.Înlocuieşte spaţiile cu _ în numele dosarelor.RaporteazăNecesităNecesită cont ProwlNecesită un cont PushbulletNecesită cont PushoverNecesităCategoriaReseteazăResetează Cota acumZi resetareReporneșteRepornește SABnzbdReporneşte fără autorizareRepornim SABnzbd...RezultatReiaReia sarcinile cu prioritate ridicatăReia sarcinile cu prioritate redusăReia sarcinile cu prioritate normalăReia post-procesareReluareTimp RetenţieReîncearcăReîncearcă toateReîncearcă toateReîncearcă toate eșuateReîncearcă toate sarcinile eșuateReîncerc toate sarcinile eșuate din Istoric?Reîncearcă toate sarcinile eșuate?Rulare scriptRulare script...Rulare script utilizator %sS01E05 Dosar EpisodS01E05 Dosar SezonSABnzbd %s pornitGazdă SABnzbdParolă SABnzbdPort SABnzbdVrăjitor Pornire-Rapidă SABnzbdNume Utilizator SABnzbdVersiune SABnzbdServer Web SABnzbdSABnzbd a detectat o eroare fatală:Închidere SABnzbd terminatăSABnzbd va rula acum în fundal.Server SMTPComandă SQL Nereuşită, vedeţi jurnalSSLSâmbătăSalveazăSalvează ModificărileSalvatSalvarea %s nereuşităSalvăm..Scanează dosar urmărirePlanificare pentru un server inexistent %sPlanificareScriptCodul de ieșire a scriptului este %sScriptul a returnat codul de ieșire %s și rezultatele următoare "%s"Script-uriCautăNumăr SezonAlegeţi o limbă interfaţă web.Selectează doar dacă furnizorul dvs. permite conexiuni SSL.SelecţieTrimiteTrimite GrupTrimite notificări RSSTrimite înapoi la coadăTrimite email când un flux RSS adaugă sarcini în coadă.Trimite email când discul este plin şi SABnzbd este întrerupt.Trimite comanda group înainte de a cere articole.Trimite notificări GrowlTrimite notificări la Centru NotificăriTrimite notificări către NotifyOSDTrimis %s în coadăSortare SerialeServerServerul %s necesită utilizator/parolăServerul %s utilizează un certificat HTTPS nesigurServerul %s va fi ignorat pentru %s minuteDetalii ServerAdresă serverAdresa server "%s:%s" nu este validăAdresă server necesarăDescriere serverServer de load-balancingNumele de server nu se rezolvă la DNSParolă serverServerul a renunţat în timpul logării.Serverul necesită nume utilizator şi parolăEroare la server (codul server %s); nu am putu lua %s în data de %sServereSetează permisiunile pentru fişierele/directoarele finalizate.
În valori octale. De exemplu: "755" sau "777"Setează serverul dvs. ISP pentru trimitere email.Instalarea este acum completă!Se reia descărcarea după resetarea cotei?Arată toateArată Opţiuni EditareArată NereuşiteArată JurnalizareaNume SerialArată Nume dosarArată conexiuni activeArată detaliiArată interfațaNume.SerialNume_SerialAfişare %s până la %s din totalul %s rezultateAfişăm un rezultatÎnchidereÎnchide PCÎnchide SABnzbdÎnchidereSemnal %s prins, salvez şi ies...MărimeUnele fişiere nu au fost verificate corect cu "%s"Unele server oferă o alternativă dacă un NZB eșuează.Ne pare rău, nu am putut interpreta informațiile. Încearcă din nou.SorteazăŞir Caractere SortareSortează după VârstăSortează după Vârstă (Cel mai Nou→Cel mai Vechi)Sortează după Vârstă (Cel mai Vechi→Cel mai Nou)Sortează după Vârstă Cel mai Nou→Cel mai VechiSortează după Vârstă Cel mai Vechi→Cel mai NouSortează după Nume (A→Z)Sortează după Nume (Z→A)Sortează după Nume A→ZSortează după Nume Z→ASortează după Mărime (Cel mai Mare→Cel mai Mic)Sortează după Mărime (Cel mai Mic→Cel mai Mare)Sortează după Mărime Cel mai Mare→Cel mai MicSortează după Mărime Cel mai Mic→Cel mai MareSortareSursăSpamSpecialVitezăLimită de VitezăLimitare de VitezăRepaus PCPorneşte VrăjitorPornire RepararePornire/ÎnchidereStareOpțiuni stare și interfațăStopSe oprește...SubiectTrimiteTrimis. Vă mulțumim!DuminicăEroare suspectă în sistemul de descprcareComutatoareÎncărcare sistemDosare SistemPerfromanță Sistem (Pystone)TEXTPREA MAREInterfață tabelară
(coadă și istoric separate)SarcinăDosar TemporarDosar Descărcare TemporarEmail TestNotificări TestTest ServerTestez detalii server...Butonul "Reparare" va reporni SABnzbd şi face o reconstrucţie completă
a conţinutului coadei de descărcare , menţinând fişierele deja descărcate.
Acest lucru va modifica ordinea în coada de descărcare.Instrumentul de descărcare automată usenetCaseta de lângă numele fluxului trebuie să fie selectată pentru ca fluxul să fie verificat de obiecte noi automat.
Când un flux este adăugat , el va lua doar obiectele noi şi nu cele deja existente, cu excepţia când apăsaţi "Descărcare Forţată".Numele gazdei nu este setat.Numărul de conexiuni permis de furnizorServerul nu a răspuns în mod corect la cererea de inițiereNu sunt conexiuni stabilite. Vă rugăm să stabiliţi cel puţin o conexiune.Sunt sarcini orfane în dosarul de descărcare.
Puteţi alege în a le şterge (inclusiv fişierele) sau a le trimite înapoi în coadă.Această cheie va permite programelor terţe să adauge NZB-uri în SABnzbd.Această cheie va oferi programelor terţe acces deplin la SABnzbd.Luna aceastaAcest server nu permite SSL pe acest portSăptămâna aceastaAcest lucru va preveni reîmprospătarea când cursorul mouse-ului este deasupra coadei.Acest lucru va reporni SABnzbd.
Folosiţi-l atunci când credeţi că programul are o problemă de stabilitate.
Descărcarea va fi oprită înainte de repornire şi reluată ulterior.Acesta va trimite un email test către contul dvs.JoiA depăşit timpul alocatA depăşit timpul alocat : Încercaţi să activaţi SSL sau conectarea pe un port diferit.Timp rămasTimp ExpirareTitluCuvinte cheie din TitluFrom: %s To: %s Date: %s Subject: SABnzbd raporteaza Disc Plin Salut, SABnzbd sa oprit din descarcare, deoarece discul este aproape plin. Va rugam sa faceti loc si reluati SABnzbd manual. AziComută Adaugă NZBPrea puţin spaţiu disc forţez PAUZĂPrea multe conexiuni la serverul %sPrea multe conexiuni, vă rugăm să întrerupeţi descărcarea sau să încercaţi din nou mai târziuVârfMeniu TopTotalDepanareÎncearcă noua noastră interfață Glitter! Un design nou și optimizat pentru modul desktop și dispozitive mobile . Dute în Configurare -> General și modifică tipul de interfață.Încearcă să prezici decărcarea cu succes înaintea descărcării reale (mai lent!)Încerc 7zip cu parola "%s"Încerc verificare SFVÎncerc să descarc NZB de la %sÎncerc să setez starea unui server nexistent %sÎncerc unrar cu parola "%s"MarţiOptimizăriTipUcale UNC "%s" nu este premisă aiciNEDORITDescărcare URL nereuşită; %sURLGRABBER S-A BLOCATAcces neautorizatDeblocheazăServer nedefinit!Eroare Necunoscută în timpul decodării %sAcţiune necunoscută: %sEroare necusnoscută la autentificarea la serverul de mailDezarhiveazăDezarhivează arhivele (rar, zip, 7z) conținute în alte arhive.Numărul de arhive încorporate este prea mare [%s]Dezarhivat %s fişierele/dosarele în %sDezarhivareDezarhivare nereuşită, %sDezarhivare nereuşită, eroare CRCDezarhivare nereuşită, arhiva necesită o parolăDezarhivare eșuată, calea este prea lungăDezarhivare nereuşită, vezi jurnalDezarhivare nereuşită, nu pot găsi %sDezarhivare nereuşită, eroare scriere sau disc plin?Fişier NZB InutilizabilFișier RAR ce poate fi folositExtensii fișier nedorite în fișierul rar %sExtensii nedoriteSusActualizare Disponibilă!ÎncarcăÎncarcă NZBÎncarcă: .nzb .rar .zip .gz, .bz2ÎncărcareDurata FuncţionăriiFolosește setările globale de interfațăFoloseşte nume temporare în timpul post procesării. Dezactivaţi când sistemul dvs. nu gestionează aceasta corect.Folosit înainte ca un NZB să intre în coadă.Cache FolositUtil dacă un server de știri are mai mult decât o adresă IPv4/IPv6Dosare UtilizatorCheie UtilizatorCheie Utilizator (necesară)Utilizator logatUtilizatorul s-a autentificat în interfața webSarcina cu script a utilizatorului a eșuatNume de UtilizatorValoriVerificare reuşită cu fişierele SFVSe verificăVerificare...VersiuneFoarte scăzutăVideoRating VideoVezi Jurnal ScriptVirus/spamAŞTEAPTĂ %s secATENŢIE:ATENȚIE: Sarcina "%s" anulată datorită ratingului (%s)ATENȚIE: În fișierul RAR "%s" sunt extensii nedorite. Fișierul nedorit este %s ATENȚIE: Sarcina "%s" întrearuptă datorită ratingului (%s)Se așteaptăAvertismentAtenţie:LOCALHOST este ambiguu, folosiţi o adresă IP numericăAtenționăriDosar MonitorizatViteză Scanare Dosar MonitorizatInterfață WebMiercuriVerificare săptămânală versiuni noi SABnzbd.CândAtunci când e clar că o sarcină va eșua din cauza lipsei de date pe server(e), anulează sarcinaCând un script de utilizator returnează o ieșire diferit de codul de ieșire, sarcina v fi marcată ca fiind nereușită.Atunci când modificați adresa IP sau dacă SABnzbd este repornit sesiunea dumneavoastră va expira.Ce procent din viteza conexiuni poate fi utilizat de SABnzbd, ex. 50Ce script să fie executat pentru notificări?Cine ar trebui să spunem că a trimis email?WikiNotificări WindowsViteză de scriereXAnDosar An-LunăTrebuie să activaţi JavaScript pentru ca Plush să funcţioneze!Trebuie să seta-ţi lățimea de bandă maximă înainte de a seta o limită de viteză.Versiunea ta de UNRAR este %s, noi recomandăm versiunea %s sau mai mare.
Cheie personală API Pushbullet (necesară)[%s] Eroare "%s" în timpul unirii fişierelor[%s] Eroare "%s" în timpul dezarhivării fişierelor RAR[%s] Unit %s fişierele[%s] Niciun set par2[%s] PAR2 a primit opţiuni incorecte, verifică setările Configurare->Comutatoare[%s] Verficare Rapidă OK[%s] Reparat în %s[%s] Verificat în %s, toate fişierele sunt corecte[%s] Verificat în %s, reparare necesarămodulul _yenc ... Negăsit!articoleaudioajustare nume fişierŞtergedziziledezactivează servervot negativactivează serverfișierhorăorecuvinte cheierămasmmanualminmin.minuteneinstalatdindezactivatactivatsausau mai puținpaginăbinar par2 ... Negăsit!parolatsecsecundevezi fişier jurnalspamtextnecunoscutbinar unrar... Negăsit!binar unzip... Negăsit!videosăptămânăSABnzbd-2.3.2/locale/ru/LC_MESSAGES/SABnzbd.mo0000644000000000000000000022032213217005256016423 0ustar 00000000000000/o/d/b1 \2i3]4G5*^5'555 56656 U6`6x677&7.767>7Q7e7x7?7=8A8I8RY8[89 99$9,90999 A9 N9 Y9c9y99999)9*9 : ::/:/B:hr: ::*k;;;;; ;;;<<< << <=6=T=!s=6=-== >'> C>N>.W>'>>>>S>7? F?S?i?o?"~?8?? ??@ @ !@/@I@a@ x@@*@@@@ @@ @ @ AAA,A4AHALA SA^A oA}A(AA A-A(BEcE sE EE#EEEEE FF %F 2F?FTFeF}F F4FFSF:GHBG G GG G G(G.G)#H&MH,tH<H&HI I'3I[ImIII I I-IJ`D`Y` k` ` `` ````` aa&a5a:a @a Ka Xaya{aaaaaab bbbb b ccc 9c CcNc hcvccc2c cc ccd).d0Xdd ddd ddddddee&e,e;eMedeze ee eeeee f)f.Cf rf~ffff fffff#f gg#g +g 9g4Zg g gg3g3g.#hRhnhhhh h(hhi$iBiZi"ji&iioi),jVj3mjjj j j jj jj k k" kCkVk _kkk |k'kk(kk k k/k/-l-]l-l&l&l$m$,m3Qm3m1m1mn%n,n4n :n Fn Qn\nln}nn nnnnnnn nnn nn oo5o"o p q2#qAVqq>r=\r r rWrs,ss s>s+t4t%CD)t7Qq<Kί=:XGm۰GIBԱV JEk:5B""eY<6,V 4 ,'33[:Mʵ`_yQٶ`+FAӷ5PK8?ոJR`@ # BM`#q=*Ӻ6L@;| i 's42 MXo-- # 8GNV "-<K2Z<#7 D SS^N)CGp^'m?%y( Dre?)7BCzgc&34I=AN!cMV/i7_'1 Y fLCm %j@f,=#j 4!N8p / 0(LuDPgH \ +gL)<! ^h&Mtul8,h;=X<OE#.i,$ :GG_ !Wl(-*-,<,i:"6+HIH$mccQl7K^,z:[>Y\ YC+W/)%BA/ &G1V%" #L;*'$"@6\##55F/Y%z*@<QTp%*Pa$}, 24g C6Sh}4'9<Vc4 >BQ%d$8L`u6x_!n/RZ4N8)% [BuN,=jPY1@c&gM@#5Yw0'#4;T*!\ |G!,[5[[[IKKK=K]]3]]Mb s'%6#:Zm  :.G4v'/#F7~.Zo { K  X q  :4 bo  * q ~p</PNaq 'Y+yhM\k:.A+]<.<!K^?Do/ &Z?+_9 4(]tF!cI a VHa*J9;;u*@!4%JZ' !?HK R]nq  9     / : :O :   SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder1x05 Episode Folder1x05 Season FolderNOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:AcceptAccess deniedActionActionsAddAdd FileAdd NZBAdd ScheduleAdd ServerAdded NZBAdministrative FolderAffected CategoriesAgeAllAlwaysApply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BackBackupBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)Cannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot read %sCannot read Watched Folder %sCannot write to INI file %sCategoriesCategoryChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Complete FolderCompletedCompleted Download FolderConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConnection Successful!ConnectionsContainer WidthCould not determine connection result (%s)Current SchedulesCustomDDUPLICATEDailyDaily FoldersDate SortingDay of monthDecadeDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDualView1DualView2E.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable Date SortingEnable GrowlEnable HTTPSEnable Movie SortingEnable NotifyOSDEnable SFV-based checksEnable TV SortingEnable UnzipEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.EnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExtensionExtra PAR2 ParametersExtracting...FailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to retrieve RSS from %s: %sFailed to send e-mailFailed to standby systemFailed to start web-interfaceFailureFailure in tempfile.mkstempFatal errorFeedFetchFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Key.File setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.ForceForce DisconnectForce DownloadForumFree (Temp)Free SpaceFrequencyFridayFurther help can be found on ourGBGeneralGenerate New KeyGo to SABnzbdGo to wizardHTTPS CertificateHTTPS KeyHTTPS PortHelpHibernate PCHide Edit OptionsHide detailsHighHistoryHistory Last 10 ItemsHomeHostHost SABnzbd should listen on.How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnoring duplicate NZB "%s"InIn foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksLoading %s failedLocation for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLoggingLowLower CaseMBMatchedMax SpeedMaximum number of retries per serverMaximum retriesMeaningMinimum Free Space for Temporary Download FolderMissing Session keyMissing articlesMondayMonthMoreMovie NameMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelNZB KeyNZB added to queueNameNamingNeverNew release %s available atNew release availableNextNice ParametersNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNoneNormalNot MatchedNot enough disk space to complete downloads!Notification Sent!NotificationsNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOn FinishOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Open Informational URLOpen a Terminal window and type the line (example):OptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOrderOriginal FilenameOther MessagesPAUSEDPart NumberPasswordPassword filePassword masked in ******, please re-enterPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Permissions for completed downloadsPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Pre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge QueuePurge the History?Purge the Queue?QueueQueue First 10 ItemsQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemove NZBRemove NZB & Delete FilesRemove ServerRemoving %s failedRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Replace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.RequiresRequiresCatResetReset Quota nowReset dayRestartRestart without loginRestarting SABnzbd...ResultResumeResume post-processingRetention timeRetryRunning scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScriptsSeason NumberSelect a web interface language.Select only if your provider allows SSL connections.SelectionSend GroupSend RSS notificationsSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to NotifyOSDSent %s to queueSeries SortingServerServer %s requires user/passwordServer %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer passwordServer quit during login sequence.Server requires username and password.ServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpecialSpeedSpeed LimitSpeedlimitStandby PCStarting RepairStartup/ShutdownStatusStopStopping...SubjectSundaySwitchesSysloadSystem FoldersTEXTTOO LARGETaskTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry to predict successful completion before actual download (slower!)Trying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereURL Fetching failed; %sUnblockUnknown Error while decoding %sUnknown action: %sUnpackUnpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unusable NZB fileUpUpdate Available!UploadUptimeUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUser FoldersUsernameValuesVerified successfully using SFV filesVerifyingVerifying...VersionView Script LogWAIT %s secWARNING:WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWho should we say sent the email?WikiXYearYear-Month FoldersYou must enable JavaScript for Plush to function![%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!case-adjustedclearddaydaysdisable serverenable serverfilehhourhoursleftmmanualminmin.minsnot installedofoffonpagepar2 binary... NOT found!secsecondssee logfiletextunknownunrar binary... NOT foundunzip binary... NOT found!weekProject-Id-Version: SABnzbd-0.7.x Report-Msgid-Bugs-To: POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2013-05-05 14:50+0000 Last-Translator: Pavel Maryanov Language-Team: Russian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:31+0000 X-Generator: Launchpad (build 18511) Generated-By: pygettext.py 1.5 Не удаётся найти файлы веб-интерфейса SABnbzd в %s.
Переустановите программу.

Обнаружены сохранённые данные из другой версии SABnzbd,
но данные другой программы нельзя повторно использовать.

Возможно, стоит сначала завершить очередь в другой программе.

После этого запустите данную программу с параметром «--clean».
При этом текущая очередь и журнал будут удалены!
Служба SABnzbd читает файл «%s». Обнаружено, что отсутствует файл sqlite3.dll.

Этот файл мог быть удалён плохо настроенной антивирусной программой.
Попробуйте проверить параметры своей антивирусной программы, переустановите SABnzbd и сообщите о проблеме поставщику этого антивирусного ПО.

Службе SABnzbd требуется свободный порт TCP/IP для встроенного веб-сервера.
Был проверен порт %s на %s, но он оказался недоступен.
Возможно, этот порт используется другой программой, или служба SABnzbd уже запущена.

Перезапустите службу SABnzbd, указав другой номер порта. Службе SABnzbd требуется действительный адрес сервера для встроенного веб-сервера.
Указан недействительный адрес.
Допустимые значения: localhost и 0.0.0.0

Перезапустите службу SABnzbd, указав действительный адрес сервера. SABnzbd предоставляется БЕЗ КАКОЙ-ЛИБО ГАРАНТИИ. Это свободное программное обеспечение, и его можно распространять при соблюдении определённых условий. Она распространяется по лицензии GNU GENERAL PUBLIC LICENSE версии 2 или (по вашему выбору) любой более поздней версии. %s -> неизвестная кодировка%s => отсутствует на всех серверах, отброшен%s статей содержат несовпадающие повторы%s статей с ошибками%s статей отсутствуетКаталог %s: ошибка доступа %s%s файлов в %s%s не является правильным восьмеричным значением%s не является допустимым адресом электронной почты%s отсутствует Разрешение адреса 
Система SABnzbd успешно остановлена.
Подождите 5 секунд и щёлкните ссылку ниже.

Обновить
+ отладка+ информация+удалить+исправить+распаковатьПапка для хранения копий NZB1x05 Эпизод Папка1x05 Сезон ПапкаПРИМЕЧАНИЕ. Папки будут созданы автоматически при сохранении. Можно использовать абсолютные пути для сохранения за пределами папок по умолчанию.Данные не будут перемещены. Требуется перезапуск SABnzbd!ВОЗРАСТКлюч APIQR-код ключа APIНеправильный ключ API. Используйте в сторонней программе ключ API из раздела «Настройка -> Общие»:Отсутствует ключ API. Введите в сторонней программе ключ API из раздела «Настройка -> Общие»:ПринятьДоступ запрещёнДействиеДействияДобавитьДобавить файлДобавить NZBДобавить заданиеДобавить серверДобавлен NZBАдминистративная папкаЗадействованные категорииВозрастВсеВсегдаПрименить к выделеннымПерезапустить SABnzbd?Остановить SABnzbd?Уверены?АргументыОграничить кэш статейИдентификатор статьиОшибка проверки подлинности. Проверьте имя и пароль.Отсутствуют учётные данные. Введите в сторонней программе имя пользователя и пароль из раздела «Настройка -> Общие»:Автоматически возобновлятьЗагрузка останавливается при уменьшении свободного места до этого значения.
В байтах, после числа можно добавить K, M, G или T. Пример: «800M» или «8G»Автоматически сортировать элементы по (среднему) возрастуНазадРезервныйНедопустимое расписание %s в %s:%sНеверно сформированная статья yEnc в %sТрафикБлокировать обновление при наведении мышиВ конецКэширование статей в памяти для уменьшения количества обращений к диску.
В байтах, после числа можно добавить K, M или G. Пример: «64M» или «128M»Статей в кэше: %s (%s)Не удаётся изменить права доступа %sНе удаётся подключиться к серверу %s [%s]Не удаётся создать %s папку %sНе удаётся создать файл резервной копии для %sНе удаётся создать каталог %sНе удаётся создать конечную папку %sНе удаётся создать временный файл для %sНе удаётся найти шаблонны электронных писем в %sНе удаётся найти шаблон веб-интерфейса: %s. Выполняется попытка использовать стандартный шаблонНе удаётся запустить браузер. Возможно, он не было найденНе удаётся прочитать %sНе удаётся прочитать наблюдаемую папку %sНе удаётся записать INI-файл %sКатегорииКатегорияИзменения не были сохранены и будут потеряны.Для применения изменений необходимо перезапустить SABnzbd!Проверять перед загрузкойПроверять наличие обновленийПроверкаИнтервал проверки (в минутах, не менее 15). Если используется планировщик, этот параметр не отключён.Выберите тему.Список очисткиНе удалось очистить %s.ОчиститьСбросить счётчикиНажмите, чтобы проверить введённые данные.Если закрыть окна или вкладки браузера, служба SABnzbd НЕ будет остановлена.Полная папкаЗавершеноПапка завершённых загрузокНастройкаФайл конфигурацииКонфигурацияПодтвердите удаление журналаПодтвердите удаление очередиПодключение установлено!СоединенияШирина контейнераНе удалось определить результат подключения (%s)Текущие заданияДругойDПОВТОРежедневноПапки по днямСортировка датыДень месяцаДесяткиОшибка декодирования %sпо умолчаниюБазовая папка по умолчаниюУдалитьУдалитьУдалить всёУдаление завершеноОшибка удаленияУдалить после загрузкиУдалить все завершённые элементы из истории?Удалить все загруженные файлы?Удалить из очереди все элементы?Удалить все неудачные элементы из истории?Не удалось удалить %s!Обнаруживать повторяющиеся загрузкиотключеноHTTPS отключён, поскольку отсутствуют файлы CERT и KEYОтменитьОтключаться от серверов Usenet, если очередь пуста или приостановлена.Отключаться, если очередь пустаУведомления о нехватке места на дискеОшибка диска при создании файла %sНа диске нет места Принудительная приостановкаВыполнять дополнительную проверку по SFV-файлам.Неправильные учётные данные для ленты %sСбрасывается ли квота каждый день, неделю или месяц?У вас ещё нет поставщика услуг Usenet? Рекомендуем попробовать %s.ВнизЗагрузитьЗагрузка завершенаКаталог загрузкиНе удалось загрузитьЗагруженоЗагружено за %s со средней скоростью %sБ/сзагружаетсяЗагрузкиДвойнойВид1ДвойнойВид2Например,Например, 8 или 20ЗАШИФРОВАНОШИБКАОШИБКА: %sОШИБКА: неверная CRC-сумма для %sОШИБКА: не удаётся найти «%s»ОШИБКА: не удалось записать (%s)ост.ИзменитьИзменить данные NZBЭл. почтаУведомление по электронной почте после завершения заданияПолучательОтправительСообщение отправленоПапка шаблонов электронных писемАдрес электронной почты получателя уведомлений.Электронное письмо успешно отправленоПустоПустой NZB-файл %sОбнаружена пустая запись RSS (%s)ВключитьИспользовать сортировку по датеИспользовать GrowlВключить HTTPSИспользовать сортировку по фильмамИспользовать NotifyOSDИспользовать проверку по SFVИспользовать сортировку по ТВ-шоуРаспаковывать ZIPДоступ к интерфейсу по протоколу HTTPS.Переименовывать папкиВключите, что уменьшить использование памяти. Отключите, чтобы медленные задания не блокировали очередь.ВключенЕсли завершить путь звёздочкой (*), папки заданий не будут создаваться.Введите URLНазвание эпизодаНомер эпизодаНазвание.эпизодаНазвание_эпизодаОшибка «%s» выполнения file_join для %sОшибка «%s» выполнения par2_repair для набора %sОшибка «%s» выполнения rar_unpack для %sОшибка «%s» выполнения unzip() для %sОшибка %s выполнения par2_repair для набора %sОшибка %s: укажите действительное имя пользователя и пароль.Не удалось создать ключ SSL и сертификатНе удалось получить сведения о ТВ (%s)Ошибка импорта %sОшибка загрузки %s: обнаружен повреждённый файлОшибка удаления %sНе удалось удалить рабочий каталог (%s)Ошибка переименования «%s» и «%s»Не удалось добавить %s: удалёнНе удалось завершить работу системыТолько при ошибкахОшибка: очередь не пустая, папку нельзя изменить.Ошибка: неправильный ключ сеансаОшибка: требуется ключ сеансаОшибки и предупреждениявсеПримерРасширениеДополнительные параметры PAR2Извлечение...ОшибкаОшибка входа на сервер %sНе удалось создать (%s)Не удалось переместить %s в %sОшибка входа на почтовый серверНе удалось закрыть базу данных (см. журнал)Не удалось разорвать соединение с почтовым серверомНе удалось составить регулярное выражение поиска: %sНе удалось подключиться к почтовому серверуНе удалось перевести систему в состояние гибернацииНе удалось импортировать %s файлов из %sНе удалось установить TLS-соединениеНе удалось переместить файлыНе удалось переименовать похожий файл: %s в %sНе удалось переименовать: %s в %sНе удалось получить RSS-ленту из %s: %sНе удалось отправить электронное письмоНе удалось перевести систему в состояние снаНе удалось запустить веб-интерфейсСбойОшибка в tempfile.mkstempКритическая ошибкаЛентаЗагрузитьЗагрузказагрузка %s блоков...Загрузка дополнительных блоков...Файл %s пустой: пропущенРасширение файлаФайл, содержащий все пароли, которые будут испробованы для зашифрованных RAR-файлов.Не удалось объединить файлы %sНазвание файла или путь к сертификату HTTPS.Название файла или путь к ключу HTTPS.Набор файловНазвание файлаФильтрОтфильтровывать файлы образцов (например, образцы видео).ПерваяПапка, содержащая пользовательские шаблоны электронной почты.Папка для поиска NZB-файлов.
NZB-файлы также ищутся в архивах ZIP, RAR и TAR.GZ.Папка или путьПапкиИмя пользователя учётной записи (для электронной почты с проверкой подлинности).Пароль учётной записи (для электронной почты с проверкой подлинности).принудительныйПринудительно отключитьЗагрузить принудительноФорумсвободно (временно)свободно на дискеЧастотапятницаДополнительные сведения доступны на нашемГБОбщиеСоздать новый ключПерейти к SABnzbdЗапустить мастерСертификат HTTPSКлюч HTTPSПорт HTTPSСправкаперевести ПК в спящий режимСкрыть параметры редактированияСкрыть подробностивысокийИсторияПоследние 10 элементов историиГлавнаяАдресАдрес, по которому будет доступна служба SABnzbd.Объем, который можно загрузить в месяц (K/M/G)БЕЗДЕЙСТВИЕНЕПОЛНЫЙПараметры IONiceIRCБездействиеЕсли не указать, будет доступен только стандартный порт с HTTPS.Если снова появляется это сообщение об ошибке, попробуйте указать другой номер порта.Игнорировать образцыПропущен повторяющийся NZB-файл «%s»ВВ папкахДля загрузки из сети Usenet требуется доступ к этой сети через соответствующего поставщика услуг. Ваш поставщик услуг Интернета может предоставить вам такой доступ, однако рекомендуется использовать usenet-провайдеров класса Premium.Несовместимая лентаНайден несовместимый файл очереди. Продолжение работы невозможноНеполная папкаНеполный NZB-файл %sНеполная последовательность файлов, которые можно объединитьНеправильное описание RSS-ленты «%s»Неправильный параметрНеправильное значение для %s: %sНеправильно закодированный пароль %sНедопустимый NZB-файл %s: пропущен (причина — %s, строка — %s)Недопустимая кодировка шаблона электронного письма %sНедопустимый адрес сервера.Недопустимые данные сервераНедопустимый этап ведения журнала для %sОбратитьРекомендуется щёлкнуть страницу правой кнопкой мыши и добавить этот адрес в закладки, а затем использовать эту закладку для доступа к службе SABnzbd, работающей в фоновом режиме.Задание завершеноОбъединить файлыОбъединениеХранить несвязанные загрузки в дополнительных папкахЯзыкПоследняяПоследние предупрежденияОткрывать браузер при запускеОткрывать веб-браузер по умолчанию при запуске SABnzbd.Ограничение скоростиСсылкиОшибка загрузки %sМесто для хранения и базы данных очереди и журнала.
Изменить можно только тогда, когда очередь пуста.Место для хранения файлов журнала SABnzbd.
Требуется перезапуск SABnzbd!Место для сохранения готовых, полностью обработанных загрузок.
Можно переопределить в пользовательских категориях.Место для хранения необработанных загрузок.
Изменить можно только тогда, когда очередь пуста.Место, где будут сохраняться NZB-файлыПапка журналаЖурналнизкийНижний регистрМБСоответствующиеМакс. скоростьМаксимальное число повторных попыток для каждого сервераЧисло попытокЗначениеМинимальное свободное место в папке временной загрузкиОтсутствует ключ сеансаОтсутствуют статьипонедельникМесяцПодробнееНазвание фильмаНазвание.фильмаНазвание_фильмаПеремещениеПеремещение...Пакетные операцииОбозначение нескольких частейКлюч NZBNZB-файл добавлен в очередьНазваниеИменованиеНикогдаДоступна новая версия %s наДоступна новая версияСледующаяПараметры NiceНе найдены шаблоны электронных писемБез папокОтмена пост-обработка из-за ошибки проверкиПолучатели не указаны. Электронное письмо не отправленоНет результатовНичегообычныйНет соответствийНе хватает места на диске для завершения загрузки!Уведомление отправленоУведомленияЧисло секунд между для поисками NZB-файлов.НЕОБЯЗАТЕЛЬНЫЙ парольНЕОБЯЗАТЕЛЬНОЕ имя пользователяВыкл.По завершении:По окончании очередиДень месяца или недели (1 — понедельник), когда провайдер сбрасывает квоту. (дополнительно можно указать чч:мм)Загружать статьи только из начала очередиОбрабатывать только задания, успешно прошедшие все проверки PAR2.Используется только для удалённого сервера Growl (адрес:порт)Открыть URL с информациейОткройте окно командной сроки и введите команду (пример):ДополнительныйДополнительный NZB (необязательно)Необязательный пароль для входа.Необязательное имя пользователя для входа.Необязательный пароль для сервера GrowlИмя файла (необязательно)ПараметрыПорядокИсходное название файлаДругие сообщенияПРИОСТАНОВЛЕНОНомер частиПарольФайл паролейПароль скрыт под ******. Повторите пароль.ПутьШаблонКлючи шаблонаПриостановитьПриостановить всеПриостановить загрузку во время пост-обработкиПриостановить наПриостановить на 1 часПриостановить на 15 минутПриостановить на 3 часаПриостановить на 30 минутПриостановить на 5 минутПриостановить на 6 часовНа сколько минут приостановить?Приостановить на...Приостановить пост-обработкуПриостановленоПриостановить загрузку с началом пост-обработки и возобновить по её окончании.Приостановлен повторяющийся NZB-файл «%s»Права доступа для завершённых загрузокУчтите, что для имени компьютера 0.0.0.0 потребуется IPv6-адрес для внешнего доступаВведите данные своего основного поставщика услуг Usenet.ПортПорт, по которому будет доступна служба SABnzbd.Ошибка пост-обработки для %s (%s)Пост-обработкаОбрабатывать только проверенные заданияПост-обработкаЗапущена пост-обработкаПост-обработка была прервана (%s)Пользовательский сценарий до помещения в очередьГотовые шаблоныНажмите клавиши STARTKEY+R и введите команду (пример):ПредыдущаяНазадПриоритетВозможно, учётная запись используется где-то ещёПроблема сОбработанный результатОбработкаПрограмма не запустилась!Ход выполненияУдалитьУдалить завершённые NZBУдалить неудачные NZBУдалить неудачные NZB и стереть файлыОчистить историюУдалить NZBУдалить NZB и стереть файлыОчистить очередьУдалить историю?Очистить очередь?ОчередьПервые 10 элементов очередиИсправление очередиБыстрая проверка...Быстрая проверкаВыйтиКвотаОсталось квотыПериод квотыКвота исчерпана. Загрузка приостановленаRRSSИнтервал опроса RSS-лентRSS-лента %s была пустойЗапущено %sДиапазонРедко используемые параметры. Их описание можно просмотреть на вики-странице, доступной по кнопке «Справка».
Не изменяйте эти параметры, не изучив сначала вики-страницу, поскольку их изменение может иметь серьезные последствия.
В скобках показаны значения по умолчанию.Прочитать все лентыПрочитать лентуЧитать RSS-лентыОписание см. на вики-странице.ОбновитьЧастота обновленияЧастота обновленияОтклонитьОтносительный путь для папокосталосьУдалить NZBУдалить NZB и стереть файлыУдалить серверНе удалось удалить %sПереименоватьИсправитьОшибка исправления: недостаточно блоков восстановления (не хватает %s)ИсправлениеНе удалось исправить: %sИсправление...Заменять пробелы в названиях папокЗаменять точки в названиях папокЗаменять точки на пробелы в названиях папок.Заменять пробелы на символы подчёркивания в названиях папок.ТребуетсяТребуется категорияСброситьСбросить квотуДень сброса трафикаПерезапуститьПерезапустить без входаПерезапуск SABnzbd...РезультатВозобновитьВозобновить пост-обработкуСрок храненияПовторитьЗапуск сценарияЗапуск сценария...Запуск пользовательского сценария %sS01E05 Эпизод ПапкаS01E05 Сезон ПапкаСервер SABnzbdПароль SABnzbdПорт SABnzbdМастер быстрого запуска SABnzbdИмя пользователя SABnzbdВерсия SABnzbdВеб-сервер SABnzbdОбнаружена критическая ошибка:Завершение работы SABnzbd законченоСлужба SABnzbd теперь будет выполняться в фоновом режиме.Сервер SMTPОшибка команды SQL (см. журнал)SSLсубботаСохранитьСохранить измененияСохраненоОшибка сохранения %sСохранение...Сканировать наблюдаемую папкуРасписание для несуществующего сервера %sРасписаниеСценарийСценарииНомер сезонаВыберите язык веб-интерфейса.Включайте, только если вашим провайдером разрешены SSL-соединения.ВыбратьОтправлять группуОтправлять RSS-уведомленияОтправлять электронное письмо, когда в очередь добавляется задание из RSS-ленты.Отправлять электронное письмо, когда на диске нет места и загрузка SABnbzd приостановлена.Отправлять команду группы перед запросом статей.Отправлять уведомления в GrowlОтправлять уведомления в NotifyOSD%s отправлено в очередьСортировка сериаловСерверДля сервера %s требуется имя пользователя и парольСервер %s будет игнорироваться %s мин.Данные сервераАдрес сервераАдрес сервера «%s:%s» является недопустимым.Требуется адрес сервераПароль сервераВо время входа на сервер был выполнен выход.Для сервера требуется имя пользователя и пароль.СерверыШаблон прав доступа для завершенных файлов и/или папок.
В восьмеричном формате. Пример: «755» или «777»Укажите сервер своего провайдера для исходящей почты.Настройка завершена.Возобновлять загрузку после сброса квоты?Показать всеПоказать параметры редактированияПоказать неудачныеПоказать журналНазвание сериалаПапка с названием сериалаПоказать подробностиПоказать интерфейсНазвание.сериалаНазвание_сериалаПоказаны результаты с %s по %s из %sПоказан один результатВыключитьвыключить ПКЗакрыть SABnzbdЗавершение работыПолучен сигнал %s. Выполняется сохранение и выход...РазмерНекоторые файлы не прошли проверку «%s»СортировкаСтрока сортировкиСортировать по возрастуСортировать по возрасту от новых к старымСортировать по возрасту от старых к новымСортировать по возрасту от новых к старымСортировать по возрасту от старых к новымСортировать по названию от А до ЯСортировать по названию от Я до АСортировать по названию от А до ЯСортировать по названию от Я до АСортировать по размеру от крупных к мелкимСортировать по размеру от мелких к крупнымСортировать по размеру от крупных к мелкимСортировать по размеру от мелких к крупнымСортировкаИсточникОсобаяСкоростьОграничение скоростиОграничить скоростьперевести ПК в режим ожиданиязапуск исправленияЗапуск/остановкаСостояниеОстановитьОстановка...ТемавоскресеньеПереключателиЗагрузка системыСистемные папкиТЕКСТСЛИШКОМ БОЛЬШОЙЗадачаПапка временной загрузкиПроверить электронную почтуТестовое уведомлениеПроверить серверДанные проверки сервера...Эта кнопка перезапустит SABnzbd и полностью
перестроит содержимое очереди, не трогая уже загруженные файлы.
При этом порядок очереди будет изменён.Клиент автоматической загрузки из USENETЧтобы включить ленту и автоматически проверять обновление её содержимого, установите флажок напротив её названия.
После добавления ленты загружаться будут только новые её элементы, а не те, что были опубликованы раньше (если только на нажать кнопку «Загрузить принудительно»).Не задано имя компьютера.Количество подключений, разрешённое провайдеромПодключения не настроены. Добавьте хотя бы одно подключение.В папке загрузки есть осиротевшие задания.
Их можно удалить (вместе с файлами) или поставить обратно в очередь.По этому ключу сторонние программы смогут загружать файлы в доступ к SABnzbd.По этому ключу сторонние программы смогут получить полный доступ к SABnzbd.за этот месяцза эту неделюЭто позволит предотвратить обновление содержимого при наведении указателя мыши на очередь.Эта кнопка перезапустит SABnzbd.
Используйте её, когда программа работает нестабильно.
Загрузка будет приостановлена до перезапуска и снова возобновлена после запуска.Отправка тестового письма на указанный почтовый ящикчетвергВремя ожидания истеклоТайм-аут. Попробуйте включить SSL или использовать другой порт.Осталось времениВремя ожиданияНазваниеTo: %s From: %s Date: %s Subject: SABnzbd: на диске нет места Привет. Система SABnzbd остановила загрузку, поскольку на диске почти не осталось свободного места. Освободите место на диске и возобновите работу SABnzbd вручную. за сегодняПереключить добавление NZBПриостановка из-за нехватки места на дискеСлишком много подключений. Приостановите загрузку или повторите попытку позжеВ началоВерхнее менювсегоУстранение неполадокПопытаться спрогнозировать успешное завершение до фактической загрузки (медленнее!)Проверка SFV-суммыПопытка загрузить NZB с %sПопытка установить статус для несуществующего сервера %sПопытка распаковки RAR-архива с паролем «%s»вторникТонкая настройкаТипUUNC-путь «%s» здесь не допускаетсяНе удалось загрузить URL: %sРазблокироватьНеизвестная ошибка декодирования %sНеизвестное действие: %sРаспаковатьРаспаковка %s файлов или папок в %sРаспаковкаНе удалось распаковать: %sНе удалось распаковать: ошибка CRCОшибка распаковки: архив защищён паролемНе удалось распаковать (см. журнал)Ошибка распаковки: не удаётся найти %sНе удалось распаковать: ошибка записи или на диске нет места?Пустой NZB-файлВверхДоступно обновление!ОтправитьВремя работыИспользовать временные названия при пост-обработке. Отключите, если ваша система обрабатывает это неправильно.Используется до того, как NZB помещается в очередь.Используемый кэшПользовательские папкиИмя пользователяЗначенияПроверка SFV-сумм прошла успешноПроверкаПроверка...ВерсияПросмотреть журнал сценарияОЖИДАНИЕ %s сПРЕДУПРЕЖДЕНИЕожиданиеПредупреждениеВнимание! Имя LOCALHOST является неоднозначным. Используйте числовой IP-адрес.предупрежденийНаблюдаемая папкаЧастота сканирования наблюдаемой папкиВеб-интерфейссредаЕженедельно проверять доступность новых версий SABnzbd.ВремяОт кого будут отправляться уведомленияВики-сайтXГодПапки с годом и месяцемДля работы Plush необходимо включить JavaScript[%s] Ошибка объединения файлов: %s[%s] Ошибка распаковки RAR-файлов: %s[%s] Объединено файлов: %s[%s] Нет PAR2-файлов[%s] Программе PAR2 переданы неправильные параметры. Проверьте параметры в разделе «Настройка -> Переключатели»[%s] Быстрая проверка прошла успешно[%s] Исправлено за %s[%s] Проверено за %s. Ошибок нет[%s] Проверено за %s. Требуется исправлениеМодуль _yenc... НЕ найденcase-adjustedОчиститьдденьднейотключить сервервключить серверфайлччасчасовосталосьмвручнуюминмин.минутне установленоизвыкл.настр.Исполняемый файл par2... НЕ найденссекундсм. журналтекстнеизвестноИсполняемый файл unrar... НЕ найденИсполняемый файл unzip... НЕ найденнеделяSABnzbd-2.3.2/locale/sr/LC_MESSAGES/SABnzbd.mo0000644000000000000000000025027713217005256016435 0ustar 00000000000000|>o>dM?@ ABCD*D'DEE5E NEoE~EE EEEFFFFFF1FFG*G>GWG?GH H0H8HRHH[HH II#IV(TV}V V-VVV#Wh$Mhrh xh h hh hhh hhhh i i i'&iNi`i xi ii ii iiiiii j/j 4j>jCj;bj-jj jj jjj6kG;kk"kkkEkDl _ljlm,mBmTm%km#mmmm*n/n28n%knnn'nnn zo o oo%ooooo5p 9pEpHKpnpq q(q:qZqcmqHqor]r)r ss%sBs FsQsTsls ts~s$sss0sst$t-t4t:t?t Xt ct ntyt tttttttttt u#u(u 8uBu [u1fu"u u+uuu u v,vEvNv`vtv v v/vvvw;w CwMwmwc}w"wAx,Fx*sxx3xxxy!!y!Cy"eyyy%yyy yyz zz.z45z jz uzz z*z zzz zz z(z {*{;{P{b{w{{{ {{{{|(|M/|}||#||%| }R}<n}}}"}}~"~2~J~j~~-~~~~~~ ~  &=FL`f{     %4:O^ o| ހ ",;Nj r  Ƃ 1DK2R  ڃ)0PW`y ń Մ߄ #*1Kd Ʌڅ!)8Jaw  ʆ9.S  ɇχ# !,3JR Y g4 Lj ̈׈335.i)މ %-F(t$ !>"N&q:Ӌoۋ)Ku3Ɍ ی  '4 C M"Wz  '(>.V //Ҏ--0&^&$$я33*1^1ʐѐ֐ސ #4;X ]iqx‘ё   (3 EQk"?@2Y5A”>=ȕ + =WG,Dq z>×̗ԗڗ"!՘A9=F LYE)H`.|˚Ӛښߚ !4HPb-Û/ʛ 7AV-r"Ü#ݜ.0B$Ty ՝ܝb$] : Ȟ՞ޞ"%% K Ubjs y 0E/-]e:m ڠ %RUp=ơ!&+ AOQV1iEB+$#P)tJţ$&8'_ ŤǤˤФ ߤ   $) .<?CFIQV p{ ڥ1?q[f-VE-ʰ8$1'V5~!α #?  & 1? O%]2$"۳MLi! 8Ea~bz C8ڷ!(5,^ 3Ǹ?A;.} Ĺ*-<%j.Vպ",;OĻ$7-= k"'¼  Zt!V׾. 1<(M3v/3ڿ :V ]g'Q y='8,%5R5-:{'g& "2HU,^'*RgH|Y *+&V}): dq0;nm#*;+'@h4y& *& 2C!L+n&B.1 BO3m! !=:X ,N!6p3R.6F6} . 10-^8u b;*Z/WE:WO(1%@%f'+Q2[P7  '19L _m*~70,? ]h K$-+R9~%  &5/Iy(- 0Qp%B4P,0!Re*@ VDaL?=3JqWF4[T?2Z21c%79"1H2]& @A[S{M<BZI87 /X>8S6T370(#H!l[$& 6 Cd-'3+;_%b2$GW5;+ CWPEmuu<(!9#[$ '   # ./O &",O^ mx,& 3S8k,;O? [[F-rL#S'K-sH+#-:h7PE(-n,f 0= %#?cLr %?RA!K(&}>I# '2FKiz"-L(]!  #5Jb&  7 +Bn}%XBH2c%&$ R&y,wQ5a!.TQ/X,[,";C^P;,/  \ *i  ,       - 9@  z    N   $  1 <  R ] 8u       < \ 2x  ' & ) 0= n w 2 *,LW5I]H19H92@1HFe$ "%6\)q !$E#^1$ '@"Gj  %+QT#X| 'o> +!@ b=o19*R}m$9Q a<m8_RC !$>Zv/FDCJ. /G[o&'(!"($K&p$ 9 &N u  4 * 7 !C!(Y!! !!!!! !6!F."u" """""&"W # d# o#|#)##K#W$Kt$0$N$0@%q%% %(%,%&&5&Q&$m&1& &!& &'B2'>u'E'' (Y(4(Q2)).)))*$*@*[*w***<*,* +&+@+ S+-`++:+>+A,[,l,$~,P,P,NE-N-4-4.2M.2.H.H.FE/F// //0 0! 0!B0&d0!0)00 01 111I1 R1_1 o1'|111#11 2 22.2:C2~222+2203y4&z5K5.5T6q6UW7d78+(8T8jj88N9":3:R::: ;;1; ;<+< K<sl<<< < ="==2C>v>>^># ? .?;?N?U?1X? ?1????@&@#F@5j@@C@1@='AeA|A$A/A/A)BLGB;B/BC*CGC]C)fC C C"C C(CC?DD?E%BEhE{E7EEE/F0FGFaFrF F F(FFF F/F^*G/G GGVG.H%AH#gHH HVHIIYIfJ@kJJJJJ J(JCKUKLK,*L9WL/L+L#LM!M!MHMG*NrNN N!N NNNNNNOO(O+O 2O?O UObO eOpOxOO!OO OOO O OO O PP$P BP MPXPkPPPP SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Also test releasesAlwaysApplication TokenApplication token (required)Apply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentComplete FolderComplete folder speedCompletedCompleted Download FolderConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDisable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDualView1DualView2E.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra queue columnExtracting...FILTEREDFailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.ForceForce DisconnectForce DownloadFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGo to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHelpHibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIndexer id (%s) not found for ratings fileIndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job failedJob finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocation for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMeaningMinimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateMondayMonthMoreMore thumbs down than upMovie NameMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelNZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification Sent!NotificationsNotifyOSDNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Pre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...ResultResumeResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScriptsSearchSeason NumberSelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...SubjectSubmitSubmitted. Thank you!SundaySuspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUnauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UptimeUse global interface settingsUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User script can flag job as failedUsernameValuesVerified successfully using SFV filesVerifyingVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen the user script returns a non-zero exit code, the job will be flagged as failed.Which percentage of the linespeed should SABnzbd use, e.g. 50Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: ОZZII POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2015-12-28 10:25+0000 Last-Translator: Safihre Language-Team: Serbian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:31+0000 X-Generator: Launchpad (build 18511) SABnzbd не може да нађе датотеке веб интерфејса у %s.
Молимо да поново инстлирате програм.

SABnzbd је нашао сачуване податке неке друге верзије SABnzbd-а
али не може да искористи податке са другог програма.

Морате прво де завршите ред са другом верзијом програма.

После тога, покренути овај програм са опцијом "--clean".
То ће обрисати актуелни ред и хронилогију!
SABnzbd чита датотеку "%s". SABnzbd је нашао да недостаје датотека 'sqlite3.dll'.

Неки лоши против-вирусни програми уклањају ту датотеку.
Проверите против-вирусни програм, поново инсталирајте SABnzbd и пошаљите жалбу својим продавацу против-вируса.

SABnzbd-у је потребан слободан tcp/ip порт за интерни веб сервер.
Покушан је порт %s на %s, али није доступан.
Неки други програм користи тај порт или SABnzbd већ ради.

Поново покрените SABnzbd са другим портом. SABnzbd-у је потребна важећа хост адреса за интерни веб сервер.
Унели сте погрешну адресу.
Сигурне вредности су localhost и 0.0.0.0

Поново покренути SABnzbd са добром хост адресом. SABnzbd долази БЕЗ ИКАКВЕ ГАРАНЦИЈЕ. Ово је бесплатан програм, и ви сте добродошли да га делите под одређеним условима. Лиценциран је под GNU GENERAL PUBLIC LICENSE верзија 2 или (по вашем избору) касније верзије. %s -> Непознато енкодирање%s => фали на свим серверима, одбацивање%s артикла нису дупликате%s артикла нису добро формирани%s артикла недостају%s артикла су уклоњениФасцикла %s: %s грешка приступа%s датотека у %s%s nije ispravna oktalna vrednost%s nije ispravna email adresa%s nedostaje Решавање адресе 
Гашење SABnzbd-а је завршено.
Сачекајте око 5 секунди па кликните на линк испод.

Освежи
+ Дебаг+ Инфо+Обриши+Поправи+ИздвојФасцикла копије .нзб0 je najveći prioritet, 100 je najniži prioritet1x05 Фасцикла епизоде1x05 Фасцикла сезоне7ZIP скуп "%s" није потпун, не могу да издвојим7za program...NIJE pronađenБЕЛЕШКА: Фасцикле ће бити аутоматски креиране приликом Сачувавања. Могуће је коришћење апсолутне путање за сачувавање ван подразумеваних фасцикли.Податци неће бити премештени. Потребно поновно покретање SABnzbd-а!СТАРОСТAPI (без подешавања)API кључQR Код АПИ кључаAPI кључ је погрешан, унети у спољни програм API кључ из Подешавања->Опште:API кључ недостаје, унети у спољни програм API кључ из Подешавање->Опште:API кључ за ProwlПрекиниObustavi akoПоништи рад који не може да се завршиПоништено, не може да се завршиPrekinuto, detektovana enkripcijaPrekinuto, filter ocene se poklopio (%s)Prekinuto, detektovana neželjena ekstenzijaПрихватиПриступ одбијенАкцијаRadnje pri preuzimanju prema pravilima filtriranja.Radnja kada je otkrivena neželjena ekstenzija u RAR datotekamaАкција када је шифрован РАР преузетRadnja kada je otkrivena neželjena ekstenzijaАкцијеДодајДодај датотекуДодај NZBDodaj NZB datoteke Dodaj rasporedДодај серверНЗБ додатФасцикла АдминистратораПогођене категоријеСтаростСвеSve datoteke će biti smeštene u jedan folderSve lokalne mrežne adrese počinju sa sledećim prefiksima (najčešće "192.168.1.")Omogući balansiranje opterećenjaOmogući balansiranje opterećenja sa optimizacijom za IPv6И пробне верзијеУвекToken aplikacijeToken aplikacije (obavezan)Примени на одабраноСигурно поново покренути SABnzbd?Da li ste sigurni da želite ugasiti SABnzbd?Да ли сте сигурни?АргументиЛимит кеша артиклаИдентифација артиклаNajmanjeНајвишеАудиоOcena zvukaАутентификација погрешна, проверити име/лозинку.Недостаје аутентификација, унети у спољни програм име/лозинку из Подешавања->Опште:Automatski nastaviПаузирај када је простор испод ове вредност.
У бајтовима, опционо додати K,М,G,T. НПР: "800M" или "8G"Аутоматско сортирај ставке по старост (просек).БНазадРезервноPogrešan odgovor Pushbullet-a (%s): %sNeodgovarajući odgovor od strane Pushover (%s): %sЛоша планификација %s у %s:%sЛоше формиран yEnc артикал у %sПротокБлокирати обнове на прелаз мишаДноPregledajМодел процесораКеширати артикле у меморији. То смањује приступ диска.
У бајтовима, опционо додати K,M,G. Пример: "64M" или "128M"Кеширано %s артикла (%s)ОткажиНе може да се промене дозволе од %sNeuspešno povezivanje na server %s[%s]Не могу да креирам %s фасциклу %sNe može se kreirati sigurnosna kopija za %sНемогуће креирати фасциклу %sНемогуће креирање фасцикле %sNemoguće kreiranje privremene datoteke za %sНемогуће наћи модел е-поруке у %sНемогуће наћи веб модел: %s, програм покушава са стандардним моделомНемогуће је покренути претраживач, вероватно није нађенNemoguće pristupiti SABHelper servisuНеуспешно читање %sНеуспешно читање надгледане фасцикле %sNemoguće poslati, nedostaju obavezni podaciНе могу да пишем у бази дневника, проверите дозволе!Ne može da se upiše u INI datoteku %sКатегоријеКатегоријаПромене су изгубљене јер нису сачуване.За апликацију промена, поново покренути програм!Proveri sveПровери пре преузимањаПровери нове верзијеПровераИнтервал провере (у минутима, макар 15). Неактивно када користите планер!Odaberi izgledСписак чишћењаЧишћење %s није успело.ОчистиИспразни бројачеKliknite na dugme Ponovi test ispod, da odrediteКликнути за пробу унетих детаља.Затварање прозора/језичка претраживаче НЕЋЕ затворити SABnzbd.Lista razdvojena zarezomKomentarКомплетна фасциклаBrzina foldera za kompletirana preuzimanjaЗавршеноФасцикла за завршена преузимањаПодешавање; Датотека подешавањаПоставкеПотврда брисања хронологијеПотврда брисања редаPotvrđenoPovezivanje na %s@%s neuspešno, poruka=%sУспешно привезивање!Veza neuspešna!ВезеШирина контејнераNemoguće odrediti rezultate konekcije (%s)Не могу да издвојим %sNe mogu da zapišem. Proverite da li je u fasciklu moguće pisati.trenutni rasporediПрилагођеноПДУПЛИКАТДневноДневне фасциклеBaza dnevnika je oštećena, kreirana prazna zamenaУправљачка таблаСређивање датумомФормат датумаДан у месецуДекадаDešifrovanje %s neuspešnoПодразумеваноПодразумевана основна фасциклаОбришиОбришиИзбриши свеОбриши завршеноObriši neuspešneОбриши после преузимањаОбриши све завршене ставке са хронологије?Обриши све преузете датотеке?Обрисати све ставке са реда?Обрисати све погрешне ставке са хронологије?Neuspešno brisanje %s!Откриј дупликатна преузимањаОткриј дупле епизоде у серијеУређајUređaj na koji bi poruka trebala biti poslataUređaj(i)Uređaj(i) na koje bi poruke trebale biti poslateОнемогући управљање квотаОнемогућеноHTTPS onemogućen zbog nedostajućih CERT i KEY datotekaОдбациИскључи се са сервера када је ред празан или паузиран.Заустави везу када је ред празанОбавештење пуног дискаGreška na disku prilikom kreiranja datoteke %sДиск је пунDisk je pun! Tera PauseУради још једну проверу базирану на SFV датотеке.Немам важећу аутентификацију за фид %sКвота је ресетована сваки дан, недеље или месец?Немате 'usenet' провајдер? Препоручујемо Вам %s.ДолеПреузмиПреузимање завршеноФасцикла преузимањаНеуспешно преузимањеПреузми све par2 датотекеНеуспешно преузимање - није на вашем серверуBrzina foldera za preuzimanjeПреузимање је можда погрешно. има %s од потребних %sПреузетоПреузето за %s на просек од %sБ/сПреузимамПреузимањаDualView1DualView2Нпр.Нпр 8 или 20ШИФРИРАНОГРЕШКА:ГРЕШКА: %sГРЕШКА: Погрешан CRC у "%s"ГРЕШКА: путања је превелика (%s)ГРЕШКА: Не могу да нађем "%s"ГРЕШКА: грешка писања (%s)Процењено времеУредиУреди детаље NZB-аInače pauziraj akoЕ-поштаНотификација е-поштом при завршетку радаЕ-пошта примаоцаЕ-пошта слањаЕ-порука је послата!Фасцикла модела е-поштеАдреса на коју се шаље е-порука.Упешно слање е-поштеХитноПразноПразан NZB %sNađen prazan RSS unos (%s)ОмогућиОмогући 7zipУпали сређивање по датумуOmogući filtriranjeУпали „Growl“Активирај HTTPSУпали сортирање филмаУпали „NotifyOSD“Омогући Prowl нотификацијеOmogući Pushbullet notifikacijeOmogući Pushover notifikacijeУпали SFV провереУпали сортирање ТВ-аOmogući UnzipWindows notifikacijeПриступ интерфејсу преко HTTPS адресе.Упали преименовање фасциклеУпали за мању употребу меморије. Угасити ради спречавања блокирања реда спорим радовима.Омогући управљање квотаОмогући рекурсивни издвојОмогућеноЗавршавање путање са звездицом * ће спречити креацију фасцикле за рад.Унесите УРЛИме епизодеБрој епизодеИме.ЕпизодеИме_епизодеГрeшкaГрешка "%s" док сам покренуо 'file_join' на %sГрешка "%s" при покретања 'par2_repair' на скупу %sГрешка "%s" док сам радио 'rar_unpack' на %sГрешка "%s" при покретања 'unzip()' на %sГрешка %s при покретања 'par2_repair' на скупу %sГрешка %s: Требате да унесете важеће име/лозинку.Грешка креације SSL кључа и сертификатаГрешка преузимању ТВ инфо (%s)Грешка увоза %sГрешка учитавање %s, покварена датотека нађенаGreška pri uklanjanju %sГрешка у брисању радне фасцикле (%s)Грешка преименовања "%s" у "%s"Грешка додавања %s, уклањањеGreška pri gašenju sistemaСамо-ГрешкеGreška: Dužina putanje bi trebala biti ispod %sГрешка: ред није празан, фасцикла се не може променити.Грешка: Кључ сесије није добарГрешка: потребан је кључ сесијеГрешке/УпозорењаСвеПримериЗатвори SABnzbdЕкстензијаЕкстерни приступ интернетуДодатни параметри PAR2Ekstra kolona redaРаспакујем...FILTRIRANOНеуспешноНеуспешно пријављивање на сервер %sNeuspešno kreiranje (%s)Neuspešno premeštanje %s u %sНеуспешна аутентификација на серверу е-поштеНеуспешно затварање базе, видети извештајНеуспешно затварање везе е-поштеNeuspešna kompilacija regularne ekspresije za termin pretrage: %sНеуспешно привезивање на сервер е-поштеНеуспешна хибернација системаНеуспешан унос %s датотеке са %sNeuspešna inicijalizacija %s@%s iz razloga: %sНеуспешна иницијализација TLS везеНеуспешно премештање датотекаНеуспешно преименовање сличне датотеке: %s у %sНеуспешно преименовање : %s у %sNeuspešno ponovo pokretanje NZB nakon provere (%s)Неуспешно преузимање RSS од %s: %sНеуспешно слање Prowl порукеNeuspešno slanje e-mail porukeNeuspešno slanje Pushbullet porukeNeuspešno slanje Pushover porukeНеуспено постављање система у стању приправностиNeuspešno pokretanje web interfejsaNeuspešno pokretanje web interfejsa: ГрешкаГрешка у tempfile.mkstempФатална грешкаFatalna greška pri snimanju trenutnog stanjaFatalna greška u Assembler-uFeedПреузмиPovuci NZB sa URLДобављамУчитавање %s блокова...Преузимање екстра блокова...Датотека %s је празна, прескакањеЕкстензија датотекеДатотека са свим лозинкама за шифроване РАР датотеке.Спој датотеке %s није успелоДатотека или путања до HTTPS сертификата.Датотека или путања до HTTPS ChainДатотека или путања до HTTPS кључа.Збир датотекаИме датотекеФилтерФилтрирај примерне датотеке (нпр. видео пример).ПрвоФасцикла где се налазе модели е-поште.Фасцикла за надгледање .nzb датотека.
Такође скенира .zip .rar и .tar.gz архиве у потрази за .nzb датотекама.Фасцикла/ПутањаФасциклеАко је потребна аутентификација за слање е-поште, унети име.Ако је потребна аутентификација за слање е-поште, унети лозинку.Za servere: osiguraj da su imena kompatibilna sa Windows-om.ФорсирајНатерај искључењеНатерај преузимањеFormati: .nzb, .rar, .zip, .gz, .bz2ФорумСлободно (Привремено)Слободан просторФреквенцијаПетакOd SxxEyyЦео APIЦео веб интерфејсДаља помоћ се може наћи наГБОпштеГенериши нов кључИди на SABnzbdПокрени асистентGrowlHTTP i HTTPS portovi ne mogu biti istiHTTPS сертификатHTTPS Chain цертификатиHTTPS кључHTTPS портПомоћХибернацијаСакриј опције УређивањаСакриј детаљеSakrij/prikaži sve završene datotekeВисокХронологијаХронологија задњих 10 ставкаLimit stavki u istorijiDržite taster shift pritisnut da bi ste odabrali rasponКућаПочетна страницаХостХост на којем SABnzbd слуша.Koliko dugo ili dokle želite da pauzirate? (na engleskom!)Колико може да се преузме овог месеца (К/М/Г)ЧЕКАНЕПОТПУНОПараметри 'IONice'IPv6 adresaИРЦМирoвањеАко је празно, стандардни порт ће слушати само HTTPS.Ако опет имате ову грешку, покушајте други број.
Игнориши примереIgnoriši foldere unutar arhivaИгнорисање дуплог NZB-а "%s"УАко је "Пауза", требате да поставите лозинку и да наставите рад.U slučaju ponovnog pokretanja SABnzbd-a ovaj prozor će nestati automatski!У фасцикламаЗа преузимање са 'usenet' треба Вам приступ привајдеру. Можда Вам Ваш ISP пружа приступ, било како премијум провајдер је препоручен.Некомпатибилан ФидНекомпатибилан ред нађен, на могу да наставимНекомплетна фасциклаНепотпуна НЗБ датотека %sНепотпуна секвенца датотеке за спајањеПогрешан опис RSS фида "%s"Погрешан параметарПогрешна вредност за %s: %sPogrešno šifrovana lozinka %sIndekser id (%s) nije pronađen za datoteku ocenjivanjaИндексирањеНеважећи NZB %s, прескакање (разлог=%s, линија=%s)Погрешно енкодирање модела е-поруке %sПогрешна адреса сервера.Погрешни детаљи сервераПогрешне етапе извештаја можете наћи у хронологији за %sОкрениПрепоручено је да поставите ову локацију као 'маркер' тако да Вам је приступ SABnzbd омогућен док он ради у позадини.Неуспешан радпосао завршенПрилепити датотекеСпајањеЗадржи изгубљена преузимања у фасцикламаЈезикПоследњеНајновија УпозорењаПокрени претраживач при покретањуПокрени Веб претраживач при покретању SABnzbd-а.Ограничење брзинеЛинковиLista svih neželjenih ekstenzija. Na primer: exe or exe, comЛиста ектензије за брисање после преузимања.
На пример: nfo или nfo, sfvLista lokalnih mrežnih rasponaУчитавамUčitavanje %s neuspešnoUčitavanje %s neuspešno sa greškom %sLokalna IPv4 adresaЛокацију за ред и хронологију базе.
Промене су могуће само када је ред празан.Смештај извештаја SABnzbd-а.
Потребно је поновно покретање SABnzbd-а!Смештај завршених, процесираних преузимања.
Може се заобићи у дефинисаним категоријама.Смештај непроцесираних преузимања.
Промене су могуће само када је ред празан.Смештај за сачувавање .нзб датотека.Фасцикла извештајаБележењеIzgubljena konekcija sa SABnzbdНизакМала словаМБNapravi Windows kompatibilnimОдговараНајвећа брзинаМакс брзина линијеМакс покушаја по серверуМакс покушајаЗначењеМинимални простор за привремену фасциклуНедостаје кључ сесијеНедостају артиклиУмереноПонедељакМесецВишеViše negativnih nego pozitivnihИме филмаИме.ФилмаИме_филмаПремештањеПремештање...Мулти-операцијеЕтикете више-партијаNZB кључNZB додат у редИмеNameserver/DNS PretragaИменовањеНикадНовије издање %s је доступно наНово издање је доступноСледећеПараметри 'Nice'Без приступаНема модела е-порукеНема фасциклеНема пост-процесирање пошто провера није успелаНема примаоце, е-порука није посланаНема резултатаNije pronađen odgovarajući metod autentifikacijeНиједноНормаланНе одговараНедоступноНедовољно простора на диску за завршавање преузимања!Није коришћеноMišta nije odabrano!Центар за обавештењаОбавештење послато!ОбавештењаNotifyOSDБрој секунди између 2 провере .nzb датотекаЛозинка (ОПЦИОНО)Корисничко име (ОПЦИОНО)ИскљученоСтари ред је нађен, употребити Статус->Поправи за претварање редаНа крајуU slučaju neuspeha, pokušaj sa alternativnim NZB-omКада се ред завршиКоји дан месеца или недеље (1=понедељак) Ваш провајдер ресетује квоту? (опционо са hh:mm)Само артикли на врху редаОгранићи пост-процесирање само за радове који су прешли све PAR2 провере.Користи само удаљен „Growl“ сервер (хост:порт)Koristi ovaj server samo za sledeće kategorijeОтвори информативни УРЛОтворите прозор терминала и унети линију (пример):Otvori fasciklu završenihОпционоДодатне опције NZB-аЛозинка за аутентификацију (опционо)Корисничко име за аутентификацију (опционо)Опциона лозинка за „Growl“ серверОпционо специфирати имеОпцијеIli prevucite i pustite datoteke u prozor!РедоследОригинално име датотекеZapušteni posloviОсталоОстале порукеNeki drugi problemVan retencijeПАУЗИРАНОPar provera neuspešna na %s, dok je QuickCheck uspešan!ParametriБрој делаЛозинкаЛозинка датотекеЛозинка сакривена испод ******, поновите уносZahteva lozinkuПутањаМоделМодел кључаПаузаПаузирај свеПаузирај док се пост-процесираПаузирај заПаузирај 1 сатПаузирај 15 минутаПаузирај 3 сатаПаузирај 30 минутаПаузирај 5 минутаПаузирај 6 сатиПаузирати за колико минута?Паузирај за...Pauziraj poslove sa visokim prioritetomPauziraj poslove sa niskim prioritetomPauziraj poslove sa normalnim prioritetomПаузирај пост-процесирањеПаузираноПаузирај преузимања на почетку пост-процесирања и настави после.Паузирам због дуплог NZB-а "%s"Постатак брзине линијеДозволе за фасциклу завршених преузимањаLični API ključЛични API кључ за Prowl (потребно)Lične zabeleškeObratite pažnju, hostu 0.0.0.0 će trebati IPv6 adresa za pristup spoljaОвде унети детаље вашег примарног 'usenet' провајдера.ПортПорт на који SABnzbd чека везе.Грешка пост-процесирања за %s (%s)Накнадна обрадаПост-процесирај само проверени пословиПост-процесирањеПост-процесирање покренутоПост-процесирање је заустављено (%s)Кориснички скрипт пре-редаПредподешавањаСтиснути Startkey+R и унети линију (пример):ПретходноOnemogući balansiranje opterećenjaПретходноПриоритетMoguće deljenje nalogaПроблем саРезултат обрађивањаОбрађивањеПрограм није покренут!НапредакProwlJavna IPv4 adresaОчистиОчисти завршене NZBОчисти NZB са грешкомОчисти NZB са грешком и обриши датотекеОчисти хронологијуОчисти NZBОчисти NZB и обриши датотекеОчисти редОчисти хронологију?Очисти ред?PushbulletPushoverВерзија Python-аРедУ ред прве 10 ставкеРед завршенLimit stavku u reduПоправљење редаБрза провера...Брза ПровераИзлазКвотаОстала квотаПериод квотеKvota utrošena, pauziram preuzimanjaПRSSИнтервал RSS провереRSS фид %s је празан%s покренутоОпсегОпције ретко коришћене. За њихово значење и објашњење, клинути на дугме Помоћ за одлазак на Вики страницу.
Немојте их мењати пре не провере на Вики, пошто неке имају озбиљне нежељене ефекате.
Подразумеване вредности су између заграда.Сада читај све фидовеЧитај фидЧитај RSS фидовеPročitani svi RSS kanaliЗа више информација, читајте Вики!ОсвежиОсвежавањеБрзина освежавањаОдбациРелативност фасцикле је базираноПреосталоУклони NZBУклони NZB и обриши датотекеУклони серверUkloni sve odabrane fajloveUkloni završene posloveУклони неуспешна послаBrisanje %s neuspešnoПреименујПоправиПогрешна поправка, нема довољно блокова за поправку (фали %s)ПоправљањеNeuspešna popravka, %sPopravljanje...Ponovi testРазмени размаке у имену фасциклеРазмени тачке у имену фасциклеРазмени тачке са размацима у имену фасцикле.Размени размаке са _ у имену фасцикле.IzveštajЗахтевиПотребан Prowl налогZahteva Pushbullet nalogZahteva Pushover nalogПотребанCatРесетујРесетуј квотуДан ресетовањаПоново покрениPonovo pokreni SABnzbdPonovno pokretanje bez prijaveПоновно покретање SABnzbd-а...РезултатНаставиНастави радови са високим приоритетомНастави радови са ниским приоритетомНастави радови са нормалним приоритетомНастави пост-процесирањеNastavlja seВреме задржавањаПокушај опетPonovo pokušaj svePonovo pokušaj svePonovo pokušaj sve neuspešnePonovo pokušaj sve neuspešne poslovePokušaj ponovo sve poslove u istoriji?Ponovo pokušati sve neuspešne poslove?Покретање скриптаПокретање скипта...Покретање скрипта %sS01E05 Фасцикла епизодеS01E05 Фасцикла сезонеSABnzbd %s покренутSABnzbd хостЛозинка SABnzbd-аSABnzbd ПортАсистент брзог-покретања SABnzbd-аКорисничко име SABnzbd-аВерзија SABnzbd-аSABnzbd Веб серверSABnzbd је нашао фаталну грешку:Гашење SABnzbd је завршеноSABnzbd ће сада радити у позадини.СМТП серверNeuspešna SQL komanda, videti izveštajССЛСуботаСачувајСачувај променеСачуваноSnimanje %s neuspešnoSnimanje...Скенирај надгледану фасциклуПланификација за непостојећи сервер %sПланирањеСкриптKod prekida skripte je %sСкриптеПретрагаБрој сезонеЈезик веб интерфејсаОдабрати САМО ако Ваш провајдер допушта SSL везе.ИзборПошаљиПошаљи 'Group'Пошаљи RSS нотификацијеPošalji nazad u redПошаљи е-поруку када RSS фид дода рад у ред.Пошаљи е-поруку када је диск пун и SABnzbd паузиран.Послати команду 'group' пре тражења артикла.Пошаљи обавештења у „Growl“Пошаљи нотификације у Центру нотификацијеШаљи обавештења у „NotifyOSD“%s послат у редСортирање серијеСерверServer %s zahteva koriničko ime/lozinkuServer %s koristi nepouzdan HTTPS sertifikatServer %s će biti ignorisan %s minutaДетаљи сервераАдреса сервераAdresa servera "%s:%s" je neispravnaПотребна је адреса сервераOpis serveraBalansiranje opterećenja serveraIme servera se ne može odreditiЛозинка сервераСервер се затворио при пријављивањеСерверу су потребни име и лозинка.Greška na strani servera (kod greške %s); nemoguće dobiti %s na %sСервериПоставља дозволе за завршене датотеке/фасцикле.
У октал. На пример: "755" или "777"Унети сервер излазних е-поруке вашег провајдера.Подешавање је сада завршено!Да се настави преузимање после ресета квоте?Прикажи свеПрикажи опције УређивањаПрикажи погрешнеПокажи извештајИме серијеФасцикла Име СеријеPrikaži aktivne konekcijeПрикажи детаљеPokaži interfejsИме.серијеИме_СеријеПриказивање %s до %s од %s резултатаПриказ једног резултатаУгасиУгаси рачунарУгаси SABnzbdГашењеSignal %s primljen, snimanje i napuštanje...ВеличинаНеке датотеке нису проверене "%s"Neki serveri nude alternativni NZB pri neuspešnom preuzimanjuŽao nam je, nismo mogli to da interpretiramo. Pokušajte ponovo.СортирајУреди низСортирај по старостСреди по старост (Новије→Старије)Среди по старост (Старије→Новије)Среди по старост Новије→СтаријеСреди по старост Старије→НовијеСреди по Имену (A→Z)Среди по Имену (Z→A)Среди по имену A→ZСреди по имену Z→AСреди по величини (Веће→Мање)Среди по величини (Мање→Веће)Среди по величини Веће→МањеСреди по величини Мање→ВећеСортирањеИзворНепожељнаПосебноБрзинаОграничење брзинеОграничење брзинеУ стање приправностиПокрени чаробњакаПокретање пооправљањаПокретање/ГашењеСтатусOpcije statusa i interfejsaЗауставиЗаустављам...ТемаПошаљиPoslato. Hvala!НедељаSumnja u grešku u programu za downloadПрекидачиSysloadСистемске фасциклеPerformanse sistema (Pystone)ТЕКСТПРЕВЕЛИКОЗадатакПривременоПривремена фасцикла преузимањаПробна е-порукаProbno obaveštenjeПробај серверПробам детаље сервера...То поново покреће SABnzbd и ради пуну
реконструкцију садржаја реда, чувајући већ преузете датотеке.
То мења ред реда.Alatka za automatizovano preuzimanje sa usenet-aКутијица поред имена фида треба да буде одабрана да би фид био омогућен и да провери нове ставке.
Када је фид додат, ће узети нове ставке а не оне које су већ у RSS фиду осим ако стиснете "Натерај преузимање".Име хоста није унето.Број веза дозвољене од стране провајдераServer nije pravilno odgovorio na helo pozdravВезе нису подешене. Подесити макар једну везу.Постоје усамљени радови у фасцикли преузимања.
Можете да их обришете (укључујући датотеке) или да их поново пошаљете у ред.Кључ допушта да други програми додају NZB у SABnzbd.Овај кључ допушта пун приступ SABnzbd-а другим програмима.Овог месецаOvaj server ne dozvoljava SSL na ovom portuОве седмицеПри прелазу миша преко рада, зауставља се обнова садржаја.Ово поново покреће SABnzbd.
Користити ако мислите да програм има проблем стабилности.
Преузимање ће бити паузирано и наставиће се после.То ће послати пробну е-поруку Вашем малогу.ЧетвртакВреме је истеклоИстекло време: Покушајте да упалите SSL или да се привежете на други порт.Преостало времеВреме истеклоНасловKljučne reči nazivaZa: %s Od: %s Datum: %s Tema: SABnzbd prijavljuje Disk Pun Zdravo, SABnzbd je stao sa downloadom zato što je disk skoro pun. Molimo Vas napravite mesta i pokrenite download u SABnzbd ručno. ДанасПребаци Додај NZBPremalo prostora na disku, prisiljena PAUZAPreviše konekcija ka serveru %sПревише конекција, паузирајте преузимање или поновите каснијеВрхГлавни мениУкупноРеши проблемIsprobajte naš novi izgled Glitter! Svež, nov dizajn koji je optimizovan za desktop i mobilne uređaje. Idite na Podešavanja->Opšta da promenite izgled.Покуша да предвиди успешан завршетак пре стварног преузимања (спорије!)Покушавам 7zip са лозинком "%s"Pokušaj SFV proverePokušaj da se učita NZB sa %sПокушај постављања статуса за непостојећи сервер %sProba raspakivanja sa lozinkom "%s"УторакШтеловањеТипСUNC путања "%s" није дозвољенаNEŽELJENIПогрешно учитавање УРЛ-а; %sURLGRABBER SE SRUŠIONeautorizovan pristupДеблокирајServer nije definisan!Nepoznata greška pri dešifrovanju %sНепозната акција: %sNepoznata greška pri autentifikaciji na email serverРаспакујИздвој архиве (rar, zip, 7z) унутра архиве.Previše ugnježdenih nivoa pri raspakivanju [%s]Издвојено %s датотека/фасцикла у %sРаспакивањеNeuspešno raspakivanje, %sNeuspešno raspakivanje, CRC greškaNeuspešno raspakivanje, arhiva zahteva lozinkuNeuspešno raspakivanje, putanja je predugačkaNeuspešno raspakivanje, videti izveštajПогрешно распакивање, не може да се нађе %sNeuspašno raspakivanje, greška u pisanju ili je disk pun?NZB датотека неупотребљиваNeupotrebljiva RAR datotekaNeželjena ekstenzija je u rar datoteci %sNeželjene ekstenzijeГореНова верзија доступна!СлањеPošalji NZBPošalji: .nzb .rar .zip .gz, .bz2; РадиKoristi globalna podešavanja interfejsaКористи привремено име при пост-процесирање. Угасити уколико га Ваш систем то не прихвата како треба.Коришћено пре него што NZB уђе у ред.; КешKorisno ukoliko news server ima više od jedne IPv4/IPv6 adreseКорисничке фасциклеKorisnički ključKorisnički ključ (obavezan)Korisničke skripte mogu uznačiti posao kao neuspešanКорисничко имеВредностиУспешна провера преко СФВПроверавањеПроверавање...; ВерзијаВрло нискоВидеоOcena videaВиди извештај скриптаVirus/neželjenoЧекање %s секПАЖЊА:UPOZORENJE: Posao "%s" prekinut zbog ocene (%s)UPOZORENJE: U "%s" pronađena neželjena ekstenzija u RAR datoteci. Neželjena datoteka je %s UPOZORENJE: Posao "%s" pauziran zbog ocene (%s)ЧекамУпозорењеПажња: LOCALHOST је двосмислен, користите ИП адресе.УпозорењаНадгледана фасциклаИнтервал скенирањаВеб интерфејсСредаНедељно проверавај за новије верзије програма.КадаКада током преузимања постаје јасно да превише података недостаје, прекинути посаоKada korisnička skripta vrati kod koji nije nula, posao će biti označen kao neuspešanКоји постотак брзине линије SABnzbd треба да користи, нпр. 50Е-пошта одакле долази нотификацијаВикиWindows notifikacijeBrzina pisanjaXГодинаФасцикле Година-МесецЗа функционисање Plush-а упалите JavaScript!Требате да поставите максимални проток пре него што поставите ограничењеVerzija vašeg UNRAR-a je %s, mi preporučujemo verziju %s ili noviju.
Vaš lični Pushbullet API ključ (obavezan)[%s] Грешка "%s" при споја датотеке[%s] Greška "%s" pri raspakivanju RAR datoteka[%s] Спојено %s датотеке(а)[%s] Нема par2 датотеке[%s] 'PAR2' је примио погрешне опције, проверите параметри Подешавање->Прекидачи[%s] Брза Провера ОК[%s] Поправљено за %s[%s] Проверено за %s, све датотеке су добре[%s] Проверено за %s, потребна је поправка_yenc modul... NIJE pronađen!artikliаудиоПрилагођено-словоочистидданданаOnemogući serverdole je glasaoOmogući serverдатотекассатсата(и)кључне речиосталомручномин.мин.мин.никје инсталираноодискљ.укљ.илиili manjeстраниpar2 program...NIJE pronađen!šifrovanoсек.секунди(е)видети извештајneželjenoтекстнепознатоunrar program...NIJE pronađen!unzip program...NIJE pronađenvideoседмицаSABnzbd-2.3.2/locale/sv/LC_MESSAGES/SABnzbd.mo0000644000000000000000000021455413217005256016437 0ustar 00000000000000t>o>d=?@ ABCD*D'DD E%E >E_EnEE EEEpFxFFFFF1FFF*G.GGG?G HH H(HR8H[HHHH#I,III#fI$II II.I:I'5J']JJJJJJ J J JJJJK'KJ-KxK/KKKKKL)L*BL mL {LLLLLL L/LhM iMuM*M$N&N+N%2N#XN|NN NNNN NNqOOO OO O P(PFP!eP6P-P"PQQ"eWe\ebeue~eeeeAef'0f!Xfzffff-ff/fgg gg&g"g9ghh.h$=hbh hh th hh hhh hhhh h ii'i>iPi hi ri}i ii iiiiii ij $j.j3j;Rj-jj jj jjj6jG+ksk"kkkEkD l OlZll,m2mDm%[m#mmmm*mn2(n%[nnn'nnn jo uo oo%ooooo5o )p5pH;pnppqq*qJqc]qHqo r]zr)r s ss2s 6sAsDs\s dsns$sss0ssttt$t*t/t Ht St ^tit ptzttttttttttuu (u2u Ku1Vu"u u+uuu u u,v5v>vPvdv wv v/vvvv;v 3w=w]wcmw"wAw,6x*cxx3xxxx!y!3y"Uyxyy%yyy yyy y zz4%z Zz ezqz zz*z zzz zz z(z {{+{@{R{g{{{{ {{{{||M|m||#||%||R }<^}}}"}}}~"~:~Z~p~-x~~~~~~ ~~ -6<PVk }     $*?N _l{ ΀ЀԀ  +>Z b o|  Ђނ!42; nx Ã)ރ09@Ib  ȄЄ 4Mi Å!م!3J`u  Ά߆".< kw ɇ҇# 3; B P4q  ׈33.R)lj -/(]$Ɋ '"7&Z:oċ)4^3u Č Ќ ݌  , 6"@cv  'ҍ(׍>.?n s //--&G&n$$3ߏ31G1yǐ ͐ ِ  $A FRZaw~ב ܑ   .:T"()2B5uA>r= + &W0,-Z c>m×җ"!A"&/ 5BE̙1I.eÚȚʚ 19Kk-~/ *?-["#Ɯ.+$=bvy ŝb$F k:v Ǟ"۞% 4 >KS\ bo  0EП/FN:V à Ѡ%۠RUY=! *8:?1REBʢ+ #9)]J &!'Hp  Ȥ Ҥ   %(,/2:? Ydh p|åɥΥr`ӧ kwv')ݭ " BP%o ]el u 0̯ܯ3";Dڰ# =HbZa5 <%Fl )˲ .>H+* ޳ (: LXk"L8Uho01"+ FQW^ cDnn"t6)շ׷޷(&@$X } AY,`"!ʹ! #D5d6 Ѻ*"IM! Ļ8ͻ& -:X oR|ϼ ߼2"8U\ .6 O ] h v , &9X:pĿƿο׿2) 9 E PZw .$C.b$% (*S l1x>*IY$t,1E> BNf<G P*Z  #"@Xah|*$ .HQUj (D^~7im L   %1&5*\'$&A4=%r())$+N(z $+ 5AFN ^j ("*7,b+7)(-F,t-!3&%3L1',*'-R*( "*DKRgo L$-5'c)09 G 407D|#  #%7]`i|,  # ?Mfkt- "<.L{  6RBX wKE,4)%/D%t ( 6$Fk$ yASc t!3+N3q &8_aqS~'c (1&:afvy 1.DU[cjn   %@X_n} 92 ,HN UcGs  +:VrFu(i$n73227J#'$( E'Px @  ( 2 <.Jy '  ,=M\ vj]{((N4a )%,Ge3   $0 CMgpv*  $$. S ^ir   ):<@Z r|  # * K VbxN JT p }). '/Gd     5"Vy + ? `l{ )9&Ls* "-6&Jq!9! (5H>_?. $%Jh|)8+! 1%>dy#,3$Xl`1= \f   % 8 BO%a*(I0-^fx77553,i,**99S77  &7 H Ub u$   )C HRZi  ,y40 K=P@g 0 ZM8 = E >M        % ( I i n v }  U% {  " ; ) <  C N R )T ~       .) X+b  2 2@ s/4 !!CZ^ w #*Z$@ e?s. )$1 V ao w  *L(Clt?| *.MKRm@ !Mot5CI&"p%-\r')'-/39 KVfjlr y  #*E`f SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Also test releasesAlwaysApplication TokenApplication token (required)Apply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentComplete FolderComplete folder speedCompletedCompleted Download FolderConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDisable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDualView1DualView2E.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra queue columnExtracting...FILTEREDFailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.ForceForce DisconnectForce DownloadFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGo to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHelpHibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIndexer id (%s) not found for ratings fileIndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job failedJob finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocation for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMeaningMinimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateMondayMonthMoreMore thumbs down than upMovie NameMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelNZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification Sent!NotificationsNotifyOSDNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Pre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...ResultResumeResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScriptsSearchSeason NumberSelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...SubjectSubmitSubmitted. Thank you!SundaySuspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUnauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UptimeUse global interface settingsUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User script can flag job as failedUsernameValuesVerified successfully using SFV filesVerifyingVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen the user script returns a non-zero exit code, the job will be flagged as failed.Which percentage of the linespeed should SABnzbd use, e.g. 50Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2016-02-20 20:34+0000 Last-Translator: shypike Language-Team: Swedish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:31+0000 X-Generator: Launchpad (build 18511) SABnzbd kan inte hitta webbgränssnittets filer i %s.
Var vänlig installera om programmet.

SABnzbd har upptäckt sparad data från en annan version av SABnzbd
men kan inte återanvända datan från det andra programmet.

Färdigställ dina nedladdningar med det andra programmet först.

Därefter kan du starta det här programmet med alternativet "--clean".
Detta kommando kommer att ta bort din nuvarande kö och historik!
SABnzbd read the file "%s". SABnzbd upptäckte att filen sqlite3.dll saknas.

Det händer att bristfälligt designade virusprogram tar bort denna fil.
Var vänlig kontrollera ditt virusprogram, försök installera om SABnzbd och klaga till din återförsäljare.

SABnzbd behöver en ledig tcp/ip -port för sin interna webbserver.
Port %s på %s testades , men den är inte tillgänglig.
Någon annan applikation använder porten eller så körs redan SABnzbd.

Vänligen starta om SABnzbd med ett annat portnummer. SABnzbd behöver en giltig värdadress för dess interna webbserver.
Du har specifierat en ogiltig adress.
Säkra värdadresser är localhost och 0.0.0.0

Var vänlig starta om SABnzbd med en giltig värdadress. SABnzbd har ABSOLUT INGEN GARANTI Detta är gratis mjukvara, du är välkommen att sprida det under vissa omständigheter. Det är licensierat under GNU GENERAL PUBLIC LICENSE Version 2 eller (ditt val) en senare version. %s -> Okänd kodning%s => saknas från alla servrar, kastar%s artiklar hade icke-matchande dubletter%s artiklar var felaktiga%s artiklar saknades%s artiklar borttagna%s mapp: %s åtkomst misslyckad%s filer i %s%s är inte rätt siffervärde%s är inte en godkänd e-mail adress%s saknas Lösa adress 
SABnzbd nedstängning färdig.
Vänta ungefär 5 sekunder och klicka sedan på knappen under..

Ladda om
+ Debug+ Info+Ta bort+Reparera+Packar upp.nzb Reservmapp0 är högst prioritet, 100 är lägst prioritet1x05 Episodmapp1x05 Säsongsmapp7ZIP set "%s" är inte komplett, kan inte packa upp7za binär... EJ funnen!OBS: Mappar kommer att skapas automatiskt när du Sparar. Du måste ange exakta sökvägar till dina mappar för att spara utanför standardmapparna.Data kommer inte tas bort. Kräver omstart av SABnzbd!ÅrAPI (ingen Konfigurering)API-nyckelAPI- eller QR-kodAPI-nyckel felaktig, använd api-nyckeln från Konfiguration-> Allmänt i ditt tredjepartsprogram:API-nyckel saknas, skriv in api-nyckeln från Konfiguration-> Allmänt i ditt tredjepartsprogram:API-nyckel för ProwlAvbrytAvbryt OmAvbryt jobb som inte kan kompletterasAvbrutet, kan inte slutförasAvbruten, kryptering detekterad.Avbrutet, betyget matchade (%s)Avbruten, oönskad filändelse detekteradAccepteraÅtkomst nekadesÅtgärdAction nedladdningar enligt filtreringsregler.Händelse när en oönskad filändelse är hittad i RAR-filer.Händelse när krypterade RAR är nerladdadHändelse när oönskad filändelse hittadÅtgärderLägg tillLägg till filLägg till NZBLägg till NZB-filer Lägg till schemaLägg till serverNZB tillagdAdministrativ mappPåverkade kategorierÅlderAllaAlla filer kommer hamna i en mapp.Alla lokala nätverksadresser startar med dessa prefixer (ofta "192.168.1.")Tillåt belastningsbalanseringTillåt bellastningsbalansering med optimering för IPv6Även testutgåvorAlltidApplikations TokenApplikations token (krav)Applicera på valdaÄr du säker på att du vill starta om SABnzbd?Är du säker på att du vill stänga av SABnzbd?Är du säker?ArgumentCachestorlek för artiklarArtikel-IDMinstHögstLjudAudiobetygAutentisering misslyckades, kontrollera användarnamn och lösenord.Autentisering saknas, ange användarnamn / lösenord från Konfiguration-> Allmänt i ditt tredjepartsprogram:AutoåterupptagningAuto-pausa när fri plats är nära sin gräns.
I bytes, följt av K,M,G,T. Till exempel: "800M" or "8G"Sortera automatiskt efter (medel) ålder.BBakåtSäkerhetskopieraDålig respons från Pushbullet (%s): %sDålig respons från Pushover (%s): %sFel schema %s vid %s:%sFelaktigt utformad yEnc artikel i %sBandbreddBlock uppdaterar vid svävandeBottenBläddraCPU ModellSparar artiklar i minnet för att reducera diskåtkomst.
I bytes, följt av K,M,G. Till exempel: "64M" eller "128M"Sparat %s artiklar (%s)AvbrytDet gick inte att ändra rättigheter på %sKan ej ansluta till server %s [%s]Kan inte skapa %s mapp %sKan inte skapa backup-fil för %sKan ej skapa mapp %sKan inte skapa slutgiltig mapp %sKan inte skapa temp -fil för %sKan ej finna e-mail mallar i %sHittar inte webbmall: %s, försöker med standardmallKan inte starta webbläsaren, hittades troligtvis inteKan inte nå SABHelper tjänstenKan ej läsa %sKan ej läsa övervakad mapp %sKunde inte skicka, saknar nödvändig dataKan inte skriva till historikdatabasen, kontrollera åtkomsträttigheter!Kan inte skriva till INI filen %sKategorierKategoriÄndringarna har inte sparats och kommer att försvinna.Ändringar kräver omstart av SABnzbd!Markera allaKontrollera innan nerladdningKolla efter ny utgåvaKontrollerarKontrollintervall (i minuter, minst 15). Ej aktiv om du använder Schemaläggaren!Välj ett skin.Rensa listaRensning av %s misslyckades.RensaNollställ räknareKlicka på "Gör om test" nedan för att bestämmaKlicka här för att testa dina angivna serveruppgifter.SABnzbd kommer inte att stängas av om du stänger ett fönster eller en tab i webbläsaren.Kommaseparerad listaKommentarFärdig mappKomplett mapphastighetFärdigFärdig nedladdningsmappKonfigurationKonfig filKonfigurationBekräfta Historik-borttagningarBekräfta Kö-borttagningarBekräftadAnslutning %s@%s misslyckades, meddelande=%sAnslutning lyckades!Anslutning misslyckades!AnslutningarBredd av webbplatsDet gick inte att ansluta (%s)Kunde inte packa upp %sKunde inte skriva. Kontrollera att sökvägen är skrivbarAktuella schemanAnpassaDDUBLETTDagligenDagliga mapparSkadad hitsotrikdatabas, skapade en tom ersättareInstrumentpanelDatum sorteringDatumformatMånadsdagÅrtiondeAvkodning av %s misslyckadesStandardStandard basmappTa bortTa bortTa bort allaBorttagning färdigBorttagning MisslyckadesTa bort efter nedladdningTa bort alla slutförda objekt från Historik?Ta bort alla nedladdade filer?Ta bort alla saker från kön?Ta bort alla felaktiga saker från historiken?Borttagning av %s misslyckades!Upptäck dubbletter av nedladdningarHitta dublettavsnitt i serierEnhetEnheter där meddelande skall skickasEnhet(er)Enhet(er) där medellandet skall skickasAvaktivera kvothanteringAvaktiveradAvaktiverade HTTPS då CERT och KEY -filer saknasKastaKoppla ifrån usenet servrarna när kön är tom eller pausad.Koppla ifrån när kön är tomFull hårddisk notifieringDiskfel vid skapande av fil %sDisken är fullDisken är full! Pausar...Gör en extra kontroll med SFV filerHar inte giltig autentisering för flöde %sNollställs kvoten varje dag, vecka eller månad?Har du inte någon usenet leverantör? Vi rekommenderar att prova %s.NerNedladdningHämtningen slutfördesTemporär nedladdningmappHämtning misslyckadesLadda ner alla par2 filerNerladdning misslyckades - Inte på din server eller servrarNerladdningsmapphastighetNerladdningen kan misslyckas, bara %s av krävda %s finns tillgängligtNedladdadHämtade i %s vid ett genomsnitt på %sB/sLaddar nerHämtningarFlerskärm1Flerskärm2T.ex.Te.x 8 eller 20KRYPTERATFEL:FEL: %sFEL: CRC misslyckades i "%s"FEL: sökvägen är för lång (%s)FEL: gick inte att hitta "%s"FEL: skrivningsfel (%s)Tid kvarÄndraÄndra NZB detaljerAnnars Pausa OmE-postE-post notifiering när jobb är slutförtE-post mottagareE-post avsändareSkickat E-mail!Mapp för E-mail mallarE-postadress att skicka e-post till.E-mail sändning lyckadesNödfallTomNZB filen %s är tomTom RSS post hittades (%s)AktiveraAktivera 7zipAktivera datumssorteringAktivera FiltreringAktivera GrowlHTTPS AktiveraAktivera filmsorteringAktivera NotifyOSDAktivera Prowl-notiserAktivera Pushbullet-notiserAktivera Pushover-notiserAnvänd SFV-baserade kontrollerAktivera TV sorteringAktivera UnzipAktivera Windows-notiserAktivera åtkomst till webbkontrollen med HTTPS adress.Döp om mapparAktivera för lägre minnesanvändning. Avaktivera för att förhindra långsamma jobb att blockera kön.Aktivera kvothanteringAktivera rekursiv uppackningAktiveradAvsluta sökvägen med en asterisk * kommer förhindra jobb att skapa mapparAnge URLEpisodnamnEpisodnummerEpisod.NamnEpisod_NamnFelFel "%s" när du kör file_join på %sFel "%s" medans par2_repair kördes på %sFel "%s" när du kör rar_unpack på %sFel "%s" när du kör unzip() på %sFel %s när du kör par2_repair på %sError %s: Du måste ange ett giltigt användarnamn och lösenord.Det gick inte att skapa SSL-nyckel eller certifikat.Det gick inte att hämta TV info (%s)Det gick inte att importera %sLaddningsfel %s, felaktig fil detekteradFel vid borttagning av %sDet gick inte att ta bort arbetsmapp (%s)Det gick inte att döpa om "%s" till "%s"Det gick inte att lägga till %s, tar bortFel uppstod då systemet skulle stängasBara vid felFel: Sökvägen skall vara under %s.Fel: Kön är inte tom, kan inte byta mapp.Fel: Fel sessionsnyckelFel: Kräver sessionsnyckelFel/VarningAlltExempelAvsluta SABnzbdFiländelseExtern internetåtkomstExtra PAR2 parametrarExtra kökolumnExtraherar...FILTRERADMisslyckadesDet gick inte att logga in på server %sSkapande av (%s) misslyckadesDet gick inte att flyta %s till %sAutentisering till mailserver misslyckadesDet gick inte att stänga databasen, se loggDet gick inte att stänga e-mail anslutningDet gick inte att kompilera regex för sök-sträng: %sDet gick inte att ansluta till mailserverKunde inte sätta systemet i väntelägeDet gick inte att importera %s filer från %sMisslyckades att initiera %s@%s med orsak %sDet gick inte att initialisera TLS anslutningMisslyckades med att flytta filerDet gick inte att döpa om liknande fil: %s till %sDet gick inte att döpa om: %s till %sMisslyckades att starta om NZB efter för-koll (%s)Det gick inte att hämta RSS flödet från %s: %sMisslyckades att skicka ProwlmeddelandeDet gick inte att skicka e-mailMisslyckades att skicka pushbulletmeddelandeMisslyckades att skicka pushovermeddelandeDet gick inte att sätta systemet i vilolägeDet gick inte att starta webbgränssnittetMisslyckades att starta webbgränsnitt: MisslyckadesFel i tempfile.mkstempAllvarligt felKritiskt fel vid sparande av lägeKritiskt fel i AssemblerFlödeHämtaHämta NZB från URLHämtarHämtar %s block...Hämtar extra block...Fil %s är tom, hoppar överFiländelseFil som innehåller alla lösenord som ska prövas på krypterade RAR-filer.Filsammanslagning av %s misslyckadesFilnamn eller sökväg till HTTPS Certifikat.Filnamn eller sökväg till HTTPS-kedjaFilnamn eller sökväg till HTTPS Nyckel.FiluppsättningFilnamnFilterFiltrera ut sample-filer (ex. video samplingar).FörstaMapp som innehåller användar-definierade e-mail mallar.Mapp som igenomsöks automatiskt efter .nzb filer.
Skannar även igenom .zip .rar och .tar.gz arkiv efter .nzb filer.Mapp/SökvägMapparAnvändarnamn för e-post som kräver autentisering.Lösenord för e-post som kräver autentisering.För servrar: Gör att namn är kompatibla med Windows.TvingaTvinga frånkopplingTvinga nedladdningFormat: .nzb, .rar, .zip, .gz, .bz2ForumLedigt temputrymmeLedigt diskutrymmeFörekomstFredagFrån SxxEyyFull APIFullt WebgränsnittÖvrig hjälp kan du hitta på våranGBAllmäntGenerera Ny NyckelGå till SABnzbdGå till guidenGrowlHTTP och HTTPS portar kan inte vara likadanaHTTPS CertifikatHTTPS-kedjecertifikatHTTPS NyckelHTTPS-portHjälpViloläge PCDölj RedigeringsalternativGöm detaljerVisa/göm färdiga filerHögHistorikHistorik (10 senaste sakerna)Historik artikelgränsHåll in shiftknappen för att välja omfångHemWebbplatsAdressAdress som SABnzbd ska lyssna på.Hur lång tid eller tills då vill du pausa? (på engelska!)Hur mycket kan laddas ner denna månad (K/M/G)VäntarINKOMPLETTIONice parametrarIPv6-adressIRCInaktivOm tom kommer standardporten endast lyssna till HTTPS.Om du får detta felmeddelande igen, var vänlig försök med en annan siffra.
Ignorera Sample-filerIgnorera alla mappar i arkivenIgnorerar dubblett för NZB "%s"IOm "Pausad", så behöver du ange ett lösenord för att återuppta jobbet.Om SABnzbd startar om kommer denna skärm att försvinna automatiskt!In mappFör att ladda ner från usenet du behöver tillgång till en leverantör. Din internetleverantör kan ge dig tillgång, men en premie leverantör rekommenderas.Inkompatibel feedFelaktig köfil funnen, kan ej fortsättaOfullständig mappNZB filen %s är inte komplettEj komplett sekvens av filer för ihopläggningFelaktigt RSS-flödesbeskrivning "%s"Fel parameterFel värde för %s: %sFelaktigt kodat lösenord %sIndex id (%s) inte hittad för betygsfilIndexerarFelaktig NZB fil %s, hoppar över (orsak=%s, linje=%s)Ogiltig avkodning av email mallen %sOgiltig serveradressOgiltiga serverdetaljerFelaktig loggning i historiken av %sInverteraDet är rekommenderat att du sparar denna plats som ett bokmärke för att komma åt SABnzbd när det körs i bakgrunden.Jobb misslyckadesArbetet utfördSlår ihop filerSlår ihopLåt nedladdning i extramapp varaSpråkSistaSenaste VarningarStarta webbläsare vid uppstartStartar standard webbläsaren när SABnzbd startar.HastighetsbegränsningLänkarLista alla oönskade filändelser. Till Exempel: exe or exe, comLista av filändelser som skall bli borttagna efter nerladdning.
Till exempel: nfo or nfo, sfvLista av lokala nätverksomfångLaddarLaddning av %s misslyckadesLaddning av %s misslyckades med fel %sLokal IPv4 adressPlats för köadministration och historiedatabas.
Kan bara ändras när kön är tom.Plats för sparade loggfiler från SABnzbd.
Kräver omstart av SABnzbd!Plats för att lagra bearbetade och färdiga nedladdningar.
Kan åsidosättas av användar-definierade kategorier.Plats för att lagra ej bearbetade nedladdningar.
Kan endast ändras när kön är tom.Plats där .nzb filer sparas.LoggmappLoggningFörlorade förbindelse till SABnzbd..LågSmå bokstäverMBGör Windows-kompatibelMatchadeMax hastighetMaximal linjehastighetMax antal omförsök per serverMax antal omförsökBetyderMinimal fri plats för temporär nedladdningsmappSaknar sessionsnyckelSaknade artiklarMedelMåndagMånadMerFler tummar ner än uppFilm NamnFilm.NamnFilm_NamnFlyttarFlyttar...Multi-operationerMulti-del etikettNZB-nyckelNZB tillagd i könNamnNamnserver /DNS LookupDöpningAldrigNy utgåva %s tillgängligNy utgåva tillgängligNästaBra parametrarIngen åtkomstInga e-postmallar funnaIngen mappIngen efterbehandling på grund av misslyckad verifieringIngen mottagare angiven, ingen e-post har skickatsInga träffarIngen passande autentikationsmetod hittadesIngenNormalInte MatchadeEj tillgängligInte tillräckligt med diskutrymme för att kunna fortsätta ladda ned.Inte användInget markerat!MeddelandecenterNotis skickad!MeddelandenNotifyOSDSekunder mellan skanningar för .nzb filer.VALFRITT AnvändarlösenordVALFRITT KontoanvändarnamnAvGammal kö hittad, använd Status -> Reparera för att konvertera könVid slutNär misslyckat, prova en alternativ NZBNär kön är färdigPå vilken dag i månaden eller veckan (1=Måndag) nollställer din ISP din kvot? (Alternativt med hh:mm)Bara artiklarna för början av könEfterbehandla enbart jobb som passerat PAR2 kontrollen.Använd endast för extern Growl.server (host:port)Använd endast denna server för dessa kategorier.Öppen informations URLÖppna ett Terminal-fönster och skriv raden (exempel):Öppna färdig mappValfriValfri Kompletterande NZBVäljbart autentiserings lösenord.Väljbart autentiserings användarnamn.Valfritt lösenord för Growl-serverAlternativt ange ett filnamnAlternativEller dra och släpp filer i fönstret!OrdningOriginalfilnamnÖvergivna jobbAnnatAndra meddelandenAndra felSlut på retentionPAUSADPar verifiering misslyckades på %s, medans QuickCheck lyckades!ParametrarDelnummerLösenordLösenordsfilLösenordet är dolt med ******, försök igenLösenordskyddadSökvägMönsterHjälp till SorteringssträngPausaPausa AlltPausa nedladdning under efterbehandlingPausa förPausa 1 timmePause 15 minuterPausa 3 timmarPausa 30 minuterPausa 5 minuterPausa 6 timmarPausa hur många minuter?Pausa i...Pausa högprioriterade jobbPausa lågprioriterade jobbPausa normalprioriterade jobbPausa efterbehandlaPausadPausas nedladdning när efterbehandling börjar och återupptar nedladdning när efterbehandling är klar.Pausar dubblett för NZB "%s"Procent av linjehastighetRättigheter för färdiga nedladdningarPersonlig API-nyckelPersonlig API-nyckel för Prowl (krävs)Personliga noteringarTänk på att värdnamnet 0.0.0.0 behöver en IPv6-adress för extern åtkomstFyll i uppgifter om din primära usenet leverantör.PortPort som SABnzbd ska lyssna på.Efterbehandling misslyckades för %s (%s)EfterbehandlingEfterbehandla endast verifierade jobbEfterbehandlingEfterbehandling påbörjadEfterbehandling avbröts (%s)Kö-specifika användarskriptFörinställningarTryck på Startknappen+R och skriv raden (exempel):FöregåendeUndvik belastningsbalanseringFöregåendePrioritetMisstänkt kontodelningProblem medHanterade resultatBearbetarProgrammet startade inte!FörloppProwlPublik IPV4 adressRensaRensa färdiga NZB:erRensa Misslyckade NZB:er.Rensa Misslyckade NZB:er och ta bort filerTöm historikRensa NZB:erRensa NZB:er och ta bort filerRensa köVill du verkligen tömma historiken?Töm kön?PushbulletPushoverPython-versionKöKö (10 första sakerna)Kön färdigKö artikelgränsKöreparationSnabbkontroll...SnabbkontrollerarAvslutaKvotKvot kvarKvotperiodDin kvot är uppnådd, pausar nerladdningRRSSRSS UppdateringsintervallRSS-flödet %s var tomtKörde %sOmfångSällan använda inställningar. För deras mening och förklaring, klicka på Hjälpknappen för att komma till Wiki-sidan.
Ändra inte dessa utan att kolla med Wiki först, då vissa kan ha seriösa sidoeffekter.
Standardvärdet är mellan paranteser.Läsa Alla Flöden NuLäs flödeLäs RSS-flödenLäs alla RSS-flödenLäs Wiki Help för detta!UppdateraUppdateringsintervallUppdateringsfrekvensAvvisaRelativa mappar är baserade påÅterstårTa bort NZBTa bort NZB och filerTa bort serverTa bort alla markerade filerTa bort färdiga jobbTa bort misslyckade jobbBorttagning av %s misslyckadesRepareraMisslyckad reparation, finns ej tillräckligt med reparationsblock (%s saknas)ReparerarReparation misslyckades, %sReparerar...Gör om testErsätt mellanslag i mappnamnErsätt punkter i mappnamnErsätt punkter med mellanslag i mappnamnErsätt mellanslag med understreck i mappnamn.RapporteraKräverKräver ett Prowl-kontoKräver ett Pushbullet-kontoKräver ett Pushover-kontoKräverKatÅterställÅterställ Kvot nuNollställ dagStarta omStarta om SABnzbdStarta om utan loginStartar om SABnzbd...ResultatÅterupptaÅteruppta högprioriterade jobbÅteruppta lågprioriterade jobbÅteruppta normalprioriterade jobbÅteruppta efterbehandlaFortsätterRetensionstidFörsök igenStarta om allaStarta om allaStarta om alla mysslyckadeStarta om alla misslyckade jobbStarta om alla misslyckade jobb i historik?Starta om alla misslyckade jobb?Kör skriptKör skript...Kör användarskript %sS01E05 EpisodmappS01E05 SäsongsmappSABnzbd %s startadSABnzbd AdressSABnzbd LösenordSABnzbd-portSABnzbd Snabbstart GuideSABnzbd AnvändarnamnSABnzbd VersionSABnzbd WebbserverSABnzbd upptäckte ett allvarligt fel:SABnzbd nedstängning utförd.SABnzbd kommer nu att köras i bakgrunden.SMTP-serverSQL Kommando misslyckades, se loggSSLLördagSparaSpara ändringarSparadSparar %s misslyckadesSparar..Scanna bevakad mappSchema för icke existerande server %sSchemaläggareSkriptSkriptets utgångskod är %sSkriptSökSäsongsnummerVälj språk till webbkontrollen.Välj bara om din leverantör tillåter SSL-anslutningar.UrvalSkickaSkicka gruppSkicka RSS-notiserSkicka tillbaka i könSkicka E-post när ett RSS-flöde lägger till jobb till kön.Skicka e-mail när hårddisken är full och SABnzbd har pausat.Skicka gruppkommando innan du begär artiklar.Skicka notis till GrowlSkicka notiser till MeddelandecenterSkicka notiser till NotifyOSDSkickat %s till köSeriesorteringServerServer %s kräver användarnamn/lösenordServer %s använder ett otillförlitlig HTTPS-certifikatServer %s kommer att ignoreras i %s minuterServeruppgifterServeradressServeradressen "%s:%s" är ej giltig.Kräver serveradressServerbeskrivningServerbelastad-balanseringServernamn kunde inte läsasServerlösenordServern avslutades under inloggningServern kräver användarnamn och lösenord.Server fel (serverkod %s); kunde inte få %s på %sServrarSätt rättigheter för färdiga filer och mappar.
Använd siffror. Till exempel: "755" or "777"Ställ in din ISP's server för utgående e-mail.Installationen är nu utförd!Skall nerladdning återupptas efter att kvot är nollställd?Visa allaVisa RedigeringsalternativVisa MisslyckadeVisa loggShow NamnVisa Namn på mappVisa aktiva anslutningarVisa detaljerVisa gränssnittShow.NamnShow_NamnVisar %s till %s av %s resultatVisar ett resultatStäng AvStäng av PCStäng av SABnzbdPåbörjar nedstängning av SABnzbd..Signal %s mottagen, sparar och stänger...StorlekSome files failed to verify against "%s"Vissa servrar kan förse en alternativ NZB när en nerladdning misslyckasTyvärr, vi kunde inte tolka det. Försök igen.SorteraSorteringssträngSortera efter ålderSortera efter Ålder (Nyast→Äldst)Sortera efter Ålder (Äldst→Nyast)Sortera efter ålder Nyast→ÄldstSortera efter ålder Äldst→NyastSortera efter Namn (A→Z)Sortera efter Namn (Z→A)Sortera efter namn A→ZSortera efter namn Z→ASortera efter Storlek (Störst→Minst)Sortera efter Storlek (Minst→Störst)Sortera efter storlek Störst→MinstSortera efter storlek Minst→StörstSorteringKällaSpamSpeciellHastighetHastighetsgränsHastighetsgränsSparläge PCStarta guideStartar reparationStarta/StängStatusStatus och gränsnittsinställningarStoppStänger...ÄmneSkickaSkickat. Tack!SöndagMisstänker fel i nedladdareSwitcharSystembelastningSystemmapparSystemprestanda (Pystone)TEXTFÖR STORUppgiftTemporär MappTemporär nedladdningsmappTesta E-postTesta notifikationTestserverTestar serverdetaljer...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.Det automatiska usenet nedladdningsverktygetKryssrutan bredvid flödesnamnet ska aktiveras för att flödet automatiskt ska kontrolleras för nya objekt.
När ett flöde läggs till kommer det bara att välja nya objekt och inte allt som redan finns i RSS-flöded så länge du inte klickar på "Tvinga nedladdning".Adressen är inte angiven.Antalet anslutningar som tillåts av din leverantörServern svarade inte ordentligt till hälsningenInga anslutningar är aktiverade. Var vänlig aktivera minst en anslutning.Det finns övergivna jobb i nedladdningsmappen.
Du kan välja mellan att radera dem (inklusive filer) eller skicka tillbaka dem i kön.Denna nyckel ger tredjepartsprogram möjlighet att lägga till NZB:er i SABnzbd.Denna nyckel ger tredjepartsprogram full tillgång till SABnzbd.Denna månadDen här servern tillåter in SSL på denna portDenna veckaDetta kommer förhindra uppdaterande av innehåll när din muspekare svävar ovanför könDetta kommer att starta om SABnzbd.
Använd det när du tror att programmet har stabilitetsproblem.
Nerladdningar kommer att pusas innan omstarten och återupptas efteråt.Detta kommer att skicka ett test e-mail till ditt konto.TorsdagTimeoutTimeout: Försök aktivera SSL eller anslut via en annan port.Återstående tidTidsgränsTitelTitelns nyckelordTill: %s Från: %s Datum: %s Ämne: SABnzbd rapporterar att disk är full Hej, SABnzbd har stoppat nerladdningen på grund av att din disk inte har tillräckligt med utrymme kvar. Frigör utrymme och återuppta nerladdningen manuellt. I dagVisa/Dölj Lägg till NZBFör lite diskutrymme pausar systemetFör många anslutningar till servern %sFör många anslutningar, pausa en nedladdning eller försök igen senareToppMenyradTotaltFelsökTesta vårat nya tema Glitter! Ny fräsch design som är optimerad för stationära och mobila enheter. Gå till Inställningar -> Allmänt för att byta tema.Försök att förutspå lyckad överföring innan nerladdningen påbörjas (saktare!)Provar 7zip med lösenord "%s"Försöker verifiera SFVFörsöker att hämta NZB från %sFörsöker att sätta status på icke existerande server %sFörsöker att packa upp med lösenord %sTisdagOptimeringTypPUNC sökväg "%s" är inte tillåten härOÖNSKADURL hämtning misslyckades; %sURLGRABBER KRASHADEOtillåten åtkomstTa bort blockeringOdefinerad server!Okänt fel under avkodning av %sOkänd åtgärd: %sOkänd autentikationmisslyckande i mailservernPacka uppPacka upp arkiv (rar,zip,7z) inuti arkiven.Nästling för djup [%s]Uppackad %s filer/mappar i %sPackar uppUppackning misslyckades, %sUppackning misslyckades, CRC-felUppackning misslyckades, arkivet kräver lösenordUppackning misslyckades, sökvägen är för långUppackning misslyckades, se loggUppackning misslyckades, gick inte att hitta %sUppackning misslyckades, skrivfel eller disken full?Oanvändbar NZB filOanvändbar RAR-filOönskad filändelse i RAR-fil %sOönskade filändelserUppUppdatering tillgängligLadda uppLadda upp NZBLadda upp: .nzb .rar .zip .gz, .bz2UpptidAnvända globala gränsnittsinställningarAnvänd temporära namn under efterbehandling. Avslaget när ditt system inte stöder det.Används innan en NZB tas in i kön.Använt cacheAnvändbar om en newsserver har fler val än en IPv4/IPv6adressAnvändarmapparAnvändarnyckelAnvändarnyckel (krävs)Användarskript kan flagga jobb som misslyckatAnvändarnamnVärdenVerifieringen lyckades med SFV-filerVerifierarVerifierar...VersionMycket lågVideoVideobetygVisa skriptloggVirus/spamVÄNTA %s SEKUNDERVARNING:VARNING: Avbrutet jobb "%s" pga betyg (%s)Varning: I "%s" otillåten filändelse i RAR-filen. Otillåtna filen är %s VARNING: Pausat jobb "%s" pga betyg (%s)VäntarVarningVarning: LOCALHOST är tvetydigt, använda numerisk IP-adress .VarningarÖvervakad MappSkanningsintervall för Övervakade mapparWebbkontrollsutseendeOnsdagKolla efter ny utgåva av SABnzbd varje vecka.NärUnder nerladdning och det märks att för mycket data saknas, avbryt jobbetNär ett användarskript returnerar ett icke-nollutgångsvärde, så kommer jobbet att flaggas som misslyckatVilken procent av linjehastigheten ska SABnzbd använda, te.x 50Vem ska vi skicka e-posten från?WikiWindows-notiserSkrivhastighetXÅrÅr-Månads mapparDu måste aktivera JavaScript för Plush ska fungera!Du måste ange maximal bandbredd innan du kan ange bandbreddsgränsDin UNRAR version är %s, vi rekommenderar version %s eller högre.
Din personliga API-nyckel (krävs)[%s] Fel "%s" under filsammanslagning[%s] Fel "%s" under uppackning av RAR fil(er)[%s] Slår ihop %s filer[%s] Ingen par2 sats[%s] PAR2 har fått felaktiga alternativ, ändra dessa via Config->Switches inställningarna[%s] Snabbkontroll OK[%s] Reparerad i %s[%s] Verifierad i %s, alla filer är ok[%s] Verifiering i %s, kräver reparation_yenc modul... EJ funnen!artiklarljudversal-justeraderensaddagdagaravaktivera servernedröstadaktivera serverfilhtimmetimmarnyckelordkvarmmanuellminmin.minuterinte installeradavavdenellereller mindresidapar2 binär... EJ funnen!lösenordskyddadseksekunderse loggfilspamtextokändunrar binär... EJ funnen!unzip binär... EJ funnen!videoveckaSABnzbd-2.3.2/locale/zh_CN/LC_MESSAGES/SABnzbd.mo0000644000000000000000000023334713217005256017011 0ustar 00000000000000FL"|Do}DdDRF LGYHMI7J*NJ'yJJJJ JKK>K ^KiKK L(L/L7L?LGL1ZLLL*LLAL9M?MMNNNR*N[}NNNN#NO;O#XO$|OO OO.O:O''P'OPwPPPPP P P PPPPPP'QJ(QsQ/QQQQQ RR)!R*KR vR RRRRRR R/Rh S rS~S*T-T/T4T%;T#aTTT TTTT TTzUUU UU UV1VOV!nV6V-V"VW'W"EW6hWW WWW.W'X ?XIX_XuXS~XX XXY Y.Y"HY8kYYYYYY YZUZpZ wZ ZZZ Z#ZZ[ ['[7[*H[s[6[[[[ [[ [3[ +\ 5\ B\ N\[\b\\\\\\ \\ \\(\$] A]-b]]]#]Z]]>^^&^ ^)^^_4 _U_?]____ __,`,>`1k`5```` `aa')aQa5ga a'a a a a a ab b b$b +b5b)Obybbbbbb bb$bc )c 6cBc#Yc}c ccccc ccc d dd7dLd]dxdddd dd4 e?eSTeeeeeHe Gf Qf^f mf zff(f.f)f&g,6g<cg&ggg'gh/hKhgh h h&h-hi%iAi Pi[ici |i iiiii iijj#j>jQj%hj!jj+j jk!8k*Zk!kk'kk*k"*lMl#jll!llllm=mXm`m |mmmmmmmmmn.nA=nn'n!nnooo%o-,oZo`o/ogo p$p&,p"Sp9vpBppp qq$,qQq Wq cq nqxqq qqq qqqqGq/=r mr {rr'rrr r rrsos ss ssssss t&t +t5t:t;Yt-tt tt ttt6tG2uzu"uuuEuDv Vvavv, w9wKw%bw#wwww@wRf'y /;! ]gc"#AB,*܆3'<E!_!"Ƈ% *8> M[ls4 ƈ҈ ۈ* $ ,8 >(H q{ȉ܉ 0HcyMΊ#&%7]Rl<" CSsj%&Lb-jƍ ߍ (:@TZo Վ  $/8<G ̏ۏ .0Kko Ƒّ  < F R] wȒ ے 2 7A V co)0ѓ +I eqw Ք'CZcr x !Օ $:FOHߖ  8IYl.' Vb~  ɘ#ݘ  ,*W_n u  4՚  $;3N3.)+K!\~ -,(9H$W|!ɝߝ" &/:Vo) 33J~ ͟   "8K T` q'(>ՠ.C H T/`/--&&C$j$3311N R  $4ELi nzʤ# (/2b gs  Х"25A'iS>B= Mʩ+ DWN,Kx >ʫӫ۫"!ܬA@DM S`E0Om.Ю%.F7Ya!JA-Ͱ/԰! AK`-|6"#.B"q$ݲ  9CJbh$˳ : 6CL`#o"%ƴL 9 CPXa gt _0E5^{/ڶ :U^m %ŷRʷUMs=0!0RW m{}v1 E>B+Ǻ#)AVJh&ǻ&')Qlu { ƼȼͼӼܼ    :EI Q]bgoh]Hƿ -$1D[v$ -,#J9nzK# o|[Y_t{)* 4;K-R7/* ! .9L_ o} $C'1Yx$ #* =GNU \1ig . .Fcj 0LS m 6?'v$@Qls z$( U _ o| 0$A;Q Xeu_ ")< OY y  3 3=AJQBa .5 <IYi+y"$Y@e#*FY2`;2&M&t+5  %2$Kp8 *   *? CPY al/ *@F`p+ ) 0< O \ iv )"?bN{< GRZaiq&x.6$,*8W'!6Xx&/ 1?FMc r| !3E'`$1"*%Ms&0-Gcw"! 9!Fh DV!l ',!06Rx *$H;mH #2V] mz 3>2U !  w  07>E?c& .C3w$N*! LY34G!_8*-7X 7 %!GN`UTK Wd t '/$J+Yv `1aOsDX0@GNUs w !u *   ' 5B R _lt  !*1*\ $~9 @ J"T w  $.GHK Z!&H<g;'=Wmt& 6C J Wd t%.  , '18?O V!c  %>Z m6w#)B05s * #0Fua*$';.jn    " 3 T al     .#<L _l |      * 4 ;   1 = M "c             4 G X k  ~  +     ! ! 3; 3o           ) 0 -F t          ( / <I'b15LLG#>P_u:X%g  $ "/60O2&-A S0`/($(E_ ~  //#7G!Wy!$LA a* %(3\l      + 8N Ub q.~*>0O Vc9y977%)])''3351i1KC J Wd w -=TY8b  $  $ 0!p3!Z!@!;@"|"E"+""E"B#6#$$4#$ X$e$l$s$$,%3%$D%i%3%%%% %%[r&& &'('4F'&{'''''%' ''(;(hS(((((F)N)-_))0)),) **/*'I*7q****+*)+H+`++{+++++ + + , ,",W;,&, ,>,- -!-7-G-'e- ---:- -.. .". ).6. I.W.g.po.;.Y/pv/;/#0*0:10 l0y00 00$00<0T 1[u151(2+02\2a2 i2v2x2|2Q25263PL3(33$3 4'4T<44#4424#5<5 Z5d5k5~55555 555555 5555556 66666 #6-6%16 W6a6e6i6|666%6&666 SABnzbd cannot find its web interface files in %s.
Please install the program again.

SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s". SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number. SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address. SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. %s -> Unknown encoding%s => missing from all servers, discarding%s articles had non-matching duplicates%s articles were malformed%s articles were missing%s articles were removed%s directory: %s error accessing%s files in %s%s is not a correct octal value%s is not a valid email address%s missing Resolving address 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
+ Debug+ Info+Delete+Repair+Unpack.nzb Backup Folder0 is highest priority, 100 is the lowest priority1x05 Episode Folder1x05 Season Folder7ZIP set "%s" is incomplete, cannot unpack7za binary... NOT found!
If authentication is enabled, you will need to login again.NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.Data will not be moved. Requires SABnzbd restart!AGEAPI (no Config)API KeyAPI Key QR CodeAPI Key incorrect, Use the api key from Config->General in your 3rd party program:API Key missing, please enter the api key from Config->General into your 3rd party program:API key for ProwlAbortAbort IfAbort jobs that cannot be completedAborted, cannot be completedAborted, encryption detectedAborted, rating filter matched (%s)Aborted, unwanted extension detectedAcceptAccess deniedActionAction downloads according to filtering rules.Action when an unwanted extension is detected in RAR filesAction when encrypted RAR is downloadedAction when unwanted extension detectedActionsAddAdd FileAdd NZBAdd NZB files Add ScheduleAdd ServerAdded NZBAdministrative FolderAdvancedAffected CategoriesAgeAllAll files will go into a single folder.All local network addresses start with these prefixes (often "192.168.1.")Allow load-balancingAllow load-balancing with optimization for IPv6Also test releasesAlwaysApplication TokenApplication token (required)Apply filtersApply to SelectedAre you sure you want to restart SABnzbd?Are you sure you want to shutdown SABnzbd?Are you sure?ArgumentsArticle Cache LimitArticle identifierAt leastAt mostAudioAudio ratingAuthentication failed, check username/password.Authentication missing, please enter username/password from Config->General into your 3rd party program:Auto resumeAuto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"Automatically sort items by (average) age.BBackBackupBad response from Pushbullet (%s): %sBad response from Pushover (%s): %sBad schedule %s at %s:%sBadly formed yEnc article in %sBandwidthBlock Refreshes on HoverBottomBrowseCPU ModelCache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"Cached %s articles (%s)CancelCannot change permissions of %sCannot connect to server %s [%s]Cannot create %s folder %sCannot create backup file for %sCannot create directory %sCannot create final folder %sCannot create temp file for %sCannot find email templates in %sCannot find web template: %s, trying standard templateCannot launch the browser, probably not foundCannot reach the SABHelper serviceCannot read %sCannot read Watched Folder %sCannot send, missing required dataCannot write to History database, check access rights!Cannot write to INI file %sCategoriesCategoryCertificate verificationChanges have not been saved, and will be lost.Changes will require a SABnzbd restart!Check allCheck before downloadCheck for New ReleaseCheckingChecking interval (in minutes, at least 15). Not active when you use the Scheduler!Choose a skin.Cleanup ListCleanup of %s failed.ClearClear CountersClick on Repeat test button below to determineClick to test the entered details.Closing any browser windows/tabs will NOT close SABnzbd.Comma separated listCommentCompact layoutComplete FolderComplete folder speedCompletedCompleted Download FolderCompleted Download Folder %s is on FAT file system, limiting maximum file size to 4GBConfigConfig FileConfigurationConfirm History DeletionsConfirm Queue DeletionsConfirmedConnecting %s@%s failed, message=%sConnection Successful!Connection failed!ConnectionsContainer WidthCorrupt RAR fileCould not determine connection result (%s)Could not unpack %sCould not write. Check that the directory is writable.Current SchedulesCustomDDUPLICATEDailyDaily FoldersDamaged History database, created empty replacementDashboardDate SortingDate formatDay of monthDecadeDecoder failure: Out of memoryDecoding %s failedDefaultDefault Base FolderDelDeleteDelete AllDelete CompletedDelete FailedDelete after downloadDelete all completed items from History?Delete all downloaded files?Delete all items from the queue?Delete the all failed items from the history?Deleting %s failed!Detect Duplicate DownloadsDetect duplicate episodes in seriesDetect identical NZB files (based on items in your History or files in .nzb Backup Folder)Detect identical episodes in series (based on "name/season/episode" of items in your History)DeviceDevice to which message should be sentDevice(s)Device(s) to which message should be sentDisable quota managementDisabledDisabled HTTPS because of missing CERT and KEY filesDiscardDisconnect from Usenet server(s) when queue is empty or paused.Disconnect on Empty QueueDisk Full NotificationsDisk error on creating file %sDisk fullDisk full! Forcing PauseDo an extra verification based on SFV files.Do not have valid authentication for feed %sDoes the quota get reset each day, week or month?Don't have a usenet provider? We recommend trying %s.DownDownloadDownload CompletedDownload DirDownload FailedDownload all par2 filesDownload failed - Not on your server(s)Download folder speedDownload might fail, only %s of required %s availableDownloadedDownloaded in %s at an average of %sB/sDownloadingDownloadsDualView1DualView2Duplicate NZBE.g.E.g. 8 or 20ENCRYPTEDERROR:ERROR: %sERROR: CRC failed in "%s"ERROR: File too large for filesystem (%s)ERROR: path too long (%s)ERROR: unable to find "%s"ERROR: write error (%s)ETAEditEdit NZB DetailsElse Pause IfEmailEmail Notification On Job CompletionEmail RecipientEmail SenderEmail Sent!Email Templates FolderEmail address to send the email to.Email succeededEmergencyEmptyEmpty NZB file %sEmpty RSS entry found (%s)EnableEnable 7zipEnable Date SortingEnable FilteringEnable GrowlEnable HTTPSEnable Indexer IntegrationEnable Movie SortingEnable NotifyOSDEnable Prowl notificationsEnable Pushbullet notificationsEnable Pushover notificationsEnable SFV-based checksEnable TV SortingEnable UnzipEnable Windows NotificationsEnable accessing the interface from a HTTPS address.Enable folder renameEnable for less memory usage. Disable to prevent slow jobs from blocking the queue.Enable notification scriptEnable quota managementEnable recursive unpackingEnabledEnding the path with an asterisk * will prevent creation of job folders.Enter URLEpisode NameEpisode NumberEpisode.NameEpisode_NameErrorError "%s" while running file_join on %sError "%s" while running par2_repair on set %sError "%s" while running rar_unpack on %sError "%s" while running unzip() on %sError %s while running par2_repair on set %sError %s: You need to provide a valid username and password.Error creating SSL key and certificateError getting TV info (%s)Error importing %sError loading %s, corrupt file detectedError removing %sError removing workdir (%s)Error renaming "%s" to "%s"Error while adding %s, removingError while shutting down systemError-onlyError: Path length should be below %s.Error: Queue not empty, cannot change folder.Error: Session Key IncorrectError: Session Key RequiredErrors/WarningEverythingExampleExecutes a custom scriptExit SABnzbdExtensionExternal internet accessExtra PAR2 ParametersExtra history columnExtra queue columnExtracting...FILTEREDFail job (move to History)FailedFailed login for server %sFailed making (%s)Failed moving %s to %sFailed to authenticate to mail serverFailed to close database, see logFailed to close mail connectionFailed to compile regex for search term: %sFailed to connect to mail serverFailed to hibernate systemFailed to import %s files from %sFailed to initialize %s@%s with reason: %sFailed to initiate TLS connectionFailed to move filesFailed to rename similar file: %s to %sFailed to rename: %s to %sFailed to restart NZB after pre-check (%s)Failed to retrieve RSS from %s: %sFailed to send Prowl messageFailed to send Windows notificationFailed to send e-mailFailed to send pushbullet messageFailed to send pushover messageFailed to standby systemFailed to start web-interfaceFailed to start web-interface: Failing duplicate NZB "%s"FailureFailure in tempfile.mkstempFatal errorFatal error at saving stateFatal error in AssemblerFeedFetchFetch NZB from URLFetchingFetching %s blocks...Fetching extra blocks...File %s is empty, skippingFile ExtensionFile containing all passwords to be tried on encrypted RAR files.File join of %s failedFile name or path to HTTPS Certificate.File name or path to HTTPS Chain.File name or path to HTTPS Key.File not on serverFile setFilenameFilterFilter out sample files (e.g. video samples).FirstFolder containing user scripts.Folder containing user-defined email templates.Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.Folder/PathFoldersFor authenticated email, account name.For authenticated email, password.For servers: make sure names are compatible with Windows.For unreliable servers, will be ignored longer in case of failuresForceForce DisconnectForce DownloadForcing disconnectFormats: .nzb, .rar, .zip, .gz, .bz2ForumFree (Temp)Free SpaceFrequencyFridayFrom Show SxxEyyFrom SxxEyyFull APIFull Web interfaceFurther help can be found on ourGBGeneralGenerate New KeyGenerate new self-signed certificate and key. Requires SABnzbd restart!Glitter has some (new) features you might like!Go to SABnzbdGo to wizardGrowlHTTP and HTTPS ports cannot be the sameHTTPS CertificateHTTPS Chain CertifcatesHTTPS KeyHTTPS PortHTTPS certificate verificationHelpHelp us translate SABnzbd in your language!
Add untranslated texts or improved existing translations here:Hibernate PCHide Edit OptionsHide detailsHide/show completed filesHighHistoryHistory Last 10 ItemsHistory item limitHold shift key to select a rangeHomeHome pageHostHost SABnzbd should listen on.How long or untill when do you want to pause? (in English!)How much can be downloaded this month (K/M/G)IDLEINCOMPLETEIONice ParametersIPv6 addressIRCIdleIf empty, the standard port will only listen to HTTPS.If you get this error message again, please try a different number.
Ignore SamplesIgnore any folders inside archivesIgnoring duplicate NZB "%s"InIn case of "Pause", you'll need to set a password and resume the job.In case of SABnzbd restart this screen will disappear automatically!In foldersIn order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.Incompatible feedIncompatible queuefile found, cannot proceedIncomplete FolderIncomplete NZB file %sIncomplete sequence of joinable filesIncorrect RSS feed description "%s"Incorrect parameterIncorrect value for %s: %sIncorrectly encoded password %sIncrease performance by forcing a lower SSL encryption strength.Indexer Categories / GroupsIndexer id (%s) not found for ratings fileIndexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to "Indexer Categories / Groups" to match more categories. Use commas to separate terms. Wildcards in the terms are supported.
More information can be found on the Wiki.IndexingInvalid NZB file %s, skipping (reason=%s, line=%s)Invalid encoding of email template %sInvalid server address.Invalid server detailsInvalid stage logging in history for %sInvertIssuesIt is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.Job "%s" is probably encrypted due to RAR with same name inside this RARJob "%s" is probably encrypted: "password" in filename "%s"Job failedJob finishedJoin filesJoiningKeep loose downloads in extra foldersLanguageLastLatest WarningsLaunch Browser on StartupLaunch the default web browser when starting SABnzbd.Limit SpeedLinksList all unwanted extensions. For example: exe or exe, comList of file extensions that should be deleted after download.
For example: nfo or nfo, sfvList of local network rangesLoadingLoading %s failedLoading %s failed with error %sLocal IPv4 addressLocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!Location for queue admin and history database.
Can only be changed when queue is empty.Location of log files for SABnzbd.
Requires SABnzbd restart!Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.Location to store unprocessed downloads.
Can only be changed when queue is empty.Location where .nzb files will be stored.Log FolderLog inLog outLoggingLost connection to SABnzbd..LowLower CaseMBMake Windows compatibleMatchedMax SpeedMaximum line speedMaximum number of retries per serverMaximum retriesMeaningMinimalMinimal: when SSL is enabled, verify the identity of the server using its certificates. Strict: verify and enforce matching hostname.Minimum Free Space for Temporary Download FolderMissing Session keyMissing articlesModerateMondayMonthMoreMore thumbs down than upMovie NameMovie SortingMovie.NameMovie_NameMovingMoving...Multi-OperationsMulti-part labelNZB KeyNZB added to queueNameNameserver / DNS LookupNamingNeverNew release %s available atNew release availableNextNice ParametersNo accessNo email templates foundNo foldersNo post-processing because of failed verificationNo recipients given, no email sentNo resultsNo suitable authentication method was foundNoneNone of the enabled servers have the 'Default' category selected. Jobs in the queue that are not assigned to one of the server's categories will not be downloaded.NormalNot MatchedNot availableNot enough disk space to complete downloads!Not usedNothing selected!Notification CenterNotification ScriptNotification Sent!Notification script "%s" does not existNotificationsNotifyOSDNumber of seconds between scans for .nzb files.OPTIONAL Account PasswordOPTIONAL Account UsernameOffOld queue detected, use Status->Repair to convert the queueOn FinishOn failure, try alternative NZBOn queue finishOn which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)Only Get Articles for Top of QueueOnly external access requires loginOnly perform post-processing on jobs that passed all PAR2 checks.Only use for remote Growl server (host:port)Only use this server for these categories.Open Informational URLOpen a Terminal window and type the line (example):Open complete folderOptionalOptional Supplemental NZBOptional authentication password.Optional authentication username.Optional password for Growl serverOptionally specify a filenameOptionsOr drag and drop files in the window!OrderOriginal FilenameOrphaned jobsOtherOther MessagesOther problemOut of retentionPAUSEDPROPAGATING %s minPar verify failed on %s, while QuickCheck succeeded!ParametersPart NumberPasswordPassword filePassword masked in ******, please re-enterPasswordedPathPatternPattern KeyPausePause AllPause Downloading During Post-ProcessingPause forPause for 1 hourPause for 15 minutesPause for 3 hoursPause for 30 minutesPause for 5 minutesPause for 6 hoursPause for how many minutes?Pause for...Pause high prioirty jobsPause low prioirty jobsPause normal prioirty jobsPause post-processingPausedPauses downloading at the start of post processing and resumes when finished.Pausing duplicate NZB "%s"Percentage of line speedPermissions for completed downloadsPersonal API keyPersonal API key for Prowl (required)Personal notesPlease be aware the 0.0.0.0 hostname will need an IPv6 address for external accessPlease enter in the details of your primary usenet provider.PortPort SABnzbd should listen on.Post Processing Failed for %s (%s)Post processingPost-Process Only Verified JobsPost-processingPost-processing startedPostProcessing was aborted (%s)Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.Pre-queue script marked job as failedPre-queue user scriptPresetsPress Startkey+R and type the line (example):PrevPrevent load-balancingPreviousPriorityProbable account sharingProblem withProcessed ResultProcessingProgram did not start!ProgressPropagation delayProwlPublic IPv4 addressPurgePurge Completed NZBsPurge Failed NZBsPurge Failed NZBs & Delete FilesPurge HistoryPurge NZBsPurge NZBs & Delete FilesPurge NZBs on the current pagePurge QueuePurge the History?Purge the Queue?PushbulletPushoverPython VersionPython script "%s" does not have execute (+x) permission setQueueQueue First 10 ItemsQueue finishedQueue item limitQueue repairQuick Check...Quick CheckingQuitQuotaQuota leftQuota periodQuota spent, pausing downloadingRRAR files failed to verifyRAR files verified successfullyRSSRSS Checking IntervalRSS Feed %s was emptyRan %sRangeRarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses.Read All Feeds NowRead FeedRead RSS feedsRead all RSS feedsRead the Wiki Help on this!RefreshRefresh RateRefresh rateRejectRelative folders are based onRemainingRemember meRemove NZBRemove NZB & Delete FilesRemove ServerRemove all selected filesRemove completed jobsRemove failed jobsRemoving %s failedRemoving jobRemoving jobsRenameRepairRepair failed, not enough repair blocks (%s short)RepairingRepairing failed, %sRepairing...Repeat testReplace Spaces in FoldernameReplace dots in FoldernameReplace dots with spaces in folder names.Replace spaces with underscores in folder names.ReportRequiresRequires a Prowl accountRequires a Pushbullet accountRequires a Pushover accountRequiresCatResetReset Quota nowReset dayRestartRestart SABnzbdRestart without loginRestarting SABnzbd...Restore DefaultsResultResumeResume high prioirty jobsResume low prioirty jobsResume normal prioirty jobsResume post-processingResumingRetention timeRetryRetry AllRetry allRetry all failedRetry all failed jobsRetry all failed jobs in History?Retry all failed jobs?Running scriptRunning script...Running user script %sS01E05 Episode FolderS01E05 Season FolderSABYenc disabled: no correct version found! (Found v%s, expecting v%s)SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyencSABnzbd %s startedSABnzbd HostSABnzbd PasswordSABnzbd PortSABnzbd Quick-Start WizardSABnzbd UsernameSABnzbd VersionSABnzbd Web ServerSABnzbd detected a fatal error:SABnzbd shutdown finishedSABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads.SABnzbd will now be running in the background.SMTP ServerSQL Command Failed, see logSSLSSL CiphersSaturdaySaveSave ChangesSavedSaving %s failedSaving..Scan watched folderSchedule for non-existing server %sSchedulingScriptScript exit code is %sScript returned exit code %s and output "%s"ScriptsScripts FolderSearchSeason NumberSecure (SSL) connections from SABnzbd to newsservers and HTTPS websites will be encrypted, however, validating a server's identity using its certificates is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-date local CA certificates are required.Secure connection to serverSecuritySelect a web interface language.Select only if your provider allows SSL connections.SelectionSendSend GroupSend RSS notificationsSend back to queueSend email when an RSS feed adds jobs to the queue.Send email when disk is full and SABnzbd is paused.Send group command before requesting articles.Send notifications to GrowlSend notifications to Notification CenterSend notifications to NotifyOSDSent %s to queueSeperate multiple URLs by a commaSeries SortingServerServer %s requires user/passwordServer %s uses an untrusted HTTPS certificateServer %s uses an untrusted certificate [%s]Server %s will be ignored for %s minutesServer DetailsServer addressServer address "%s:%s" is not valid.Server address requiredServer could not complete requestServer descriptionServer load-balancingServer name does not resolveServer passwordServer quit during login sequence.Server requires username and password.Server side error (server code %s); could not get %s on %sServersSet permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"Set your ISP's server for outgoing email.Setup is now complete!Should downloading resume after the quota is reset?Show AllShow Edit OptionsShow FailedShow LoggingShow NameShow Name folderShow active connectionsShow detailsShow interfaceShow.NameShow_NameShowing %s to %s out of %s resultsShowing one resultShutdownShutdown PCShutdown SABnzbdShutting downSignal %s caught, saving and exiting...SizeSome files failed to verify against "%s"Some servers provide an alternative NZB when a download fails.Sorry, we could not interpret that. Try again.SortSort StringSort by AgeSort by Age (Newest→Oldest)Sort by Age (Oldest→Newest)Sort by Age Newest→OldestSort by Age Oldest→NewestSort by Name (A→Z)Sort by Name (Z→A)Sort by Name A→ZSort by Name Z→ASort by Size (Largest→Smallest)Sort by Size (Smallest→Largest)Sort by Size Largest→SmallestSort by Size Smallest→LargestSortingSourceSpamSpecialSpeedSpeed LimitSpeed up repairs by installing multicore Par2, it is available for many platforms.SpeedlimitStandby PCStart WizardStarting RepairStartup/ShutdownStatusStatus and interface optionsStopStopping...StrictSubjectSubmitSubmitted. Thank you!SundaySupport the project, Donate!Suspect error in downloaderSwitchesSysloadSystem FoldersSystem Performance (Pystone)TEXTTOO LARGETabbed layout
(separate queue and history)TaskTemp FolderTemporary Download FolderTest EmailTest NotificationTest ServerTesting server details...The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.The automatic usenet download toolThe checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".The hostname is not set.The number of connections allowed by your providerThe server didn't reply properly to the helo greetingThere are no connections set. Please set at least one connection.There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.This key provides identity to indexer. Check your profile on the indexer's website.This key will allow 3rd party programs to add NZBs to SABnzbd.This key will give 3rd party programs full access to SABnzbd.This monthThis prevents multiple repair runs by downloading all par2 files when needed.This server does not allow SSL on this portThis weekThis will prevent refreshing content when your mouse cursor is hovering over the queue.This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.This will send a test email to your account.ThursdayTimed outTimed out: Try enabling SSL or connecting on a different port.TimeleftTimeoutTitleTitle keywordsTo: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. TodayToggle Add NZBToo little diskspace forcing PAUSEToo many connections to server %sToo many connections, please pause downloading or try again laterTopTop MenuTotalTroubleshootTry our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.Try to predict successful completion before actual download (slower!)Trying 7zip with password "%s"Trying RAR-based verificationTrying SFV verificationTrying to fetch NZB from %sTrying to set status of non-existing server %sTrying unrar with password "%s"TuesdayTuningTypeUUNC path "%s" not allowed hereUNWANTEDURL Fetching failed; %sURLGRABBER CRASHEDUUencode detected, only yEnc encoding is supported [%s]Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running.Unauthorized accessUnblockUndefined server!Unknown Error while decoding %sUnknown SSL protocol: Try disabling SSL or connecting on a different port.Unknown action: %sUnknown authentication failure in mail serverUnpackUnpack archives (rar, zip, 7z) within archives.Unpack nesting too deep [%s]Unpacked %s files/folders in %sUnpackingUnpacking failed, %sUnpacking failed, CRC errorUnpacking failed, archive requires a passwordUnpacking failed, file too large for filesystem (FAT?)Unpacking failed, path is too longUnpacking failed, see logUnpacking failed, unable to find %sUnpacking failed, write error or disk is full?Unsuccessful login attempt from %sUnusable NZB fileUnusable RAR fileUnwanted extension is in rar file %sUnwanted extensionsUpUpdate Available!UploadUpload NZBUpload: .nzb .rar .zip .gz, .bz2UploadingUptimeUse global interface settingsUse temporary names during post processing. Disable when your system doesn't handle that properly.Used before an NZB enters the queue.Used cacheUseful if a newsserver has more than one IPv4/IPv6 addressUser FoldersUser KeyUser Key (required)User logged inUser logged in to the web interfaceUser script can flag job as failedUsernameValuesVerified successfully using SFV filesVerify certificates when connecting to indexers and RSS-sources using HTTPS.VerifyingVerifying...VersionVery LowVideoVideo ratingView Script LogVirus/spamWAIT %s secWARNING:WARNING: Aborted job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Aborted job "%s" because of rating (%s)WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s WARNING: Paused job "%s" because of encrypted RAR file (if supplied, all passwords were tried)WARNING: Paused job "%s" because of rating (%s)WaitingWarningWarning: LOCALHOST is ambiguous, use numerical IP-address.WarningsWatched FolderWatched Folder Scan SpeedWeb InterfaceWednesdayWeekly check for new SABnzbd release.WhenWhen during download it becomes clear that too much data is missing, abort the jobWhen the user script returns a non-zero exit code, the job will be flagged as failed.When your IP address changes or SABnzbd is restarted the session will expire.Which percentage of the linespeed should SABnzbd use, e.g. 50Which script should we execute for notification?Who should we say sent the email?WikiWindows NotificationsWriting speedXYearYear-Month FoldersYou can set access rights for systems outside your local network. Requires List of local network ranges to be defined.You must enable JavaScript for Plush to function!You must set a maximum bandwidth before you can set a bandwidth limitYour UNRAR version is %s, we recommend version %s or higher.
Your personal Pushbullet API key (required)[%s] Error "%s" while joining files[%s] Error "%s" while unpacking RAR files[%s] Joined %s files[%s] No par2 sets[%s] PAR2 received incorrect options, check your Config->Switches settings[%s] Quick Check OK[%s] RAR-based verification failed: %s[%s] Repaired in %s[%s] Verified in %s, all files correct[%s] Verified in %s, repair is required_yenc module... NOT found!articlesaudiocase-adjustedclearddaydaysdisable serverdownvotedenable serverfilehhourhourskeywordsleftmmanualminmin.minsnot installedofoffonoror lesspagepar2 binary... NOT found!passwordedsecsecondssee logfilespamtextunknownunrar binary... NOT foundunzip binary... NOT found!videoweekProject-Id-Version: sabnzbd Report-Msgid-Bugs-To: FULL NAME POT-Creation-Date: 2017-12-06 10:30+0000 PO-Revision-Date: 2017-06-22 07:06+0000 Last-Translator: Safihre Language-Team: Chinese (Simplified) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Launchpad-Export-Date: 2017-12-07 05:31+0000 X-Generator: Launchpad (build 18511) SABnzbd 无法找到位于 %s 的 web 界面文件。
请重新安装本程序。

SABnzbd 侦测到其他 SABnzbd 版本已保存的数据
但无法重新使用其他程序的数据。

您可能需要先完成其他程序的队列。

之后再使用 "--clean" 选项启动本程序。
该选项将清除当前队列及历史!
SABnzbd 读取到的文件是 "%s"。 SABnzbd 侦测发现缺少 sqlite3.dll 文件。

一些很差劲的病毒扫描程序会移除此文件。
请检查您的病毒扫描程序,尝试重新安装 SABnzbd 并向病毒扫描程序厂商反映。

SABnzbd 的内部 web 服务器需要一个空闲的 tcp/ip 端口。
已尝试端口 %s(位于 %s),但不可用。
有其他软件占用了该端口,或者 SABnzbd 已经在运行,

请使用其他端口号重启 SABnzbd。 SABnzbd 的内部 web 服务器需要有效的主机地址。
您指定的地址无效。
安全的值有 localhost 与 0.0.0.0

请使用适当的主机地址重启 SABnzbd。 SABnzbd *不负任何担保责任*。 这是一款自由软件,欢迎您在约定的条件下传播。 本软件依 GNU GENERAL PUBLIC LICENSE 第 2 版或 (若您愿意) 任意较新版本授权。 %s -> 未知编码%s => 所有服务器均缺失,正在舍弃%s 篇文章存在未匹配的重复%s 篇文章损坏%s 篇文章缺失已移除 %s 篇文章%s 目录: %s 访问出错%s 个文件,耗时 %s%s 不是有效的八进制值%s 不是有效的电子邮箱地址缺少 %s 正在解析地址 
SABnzbd 关闭完成。
请等待约 5 秒后点击下面的按钮。

刷新
+ 调试+ 信息+删除+修复+解压.nzb 备份文件夹0 为最高优先级,100 为最低优先级1x05 剧集文件夹1x05 季度文件夹7ZIP 分卷组 "%s" 不完整,无法解压7za 可执行程序... *未*找到!
若启用身份认证,您将需要重新登录。注: 保存时将自动创建文件夹。您可以使用绝对路径以保存到默认文件夹以外的地方。数据不会自动移动。需要重启 SABnzbd 才能生效!发布时间API (不允许配置)API KeyAPI Key QR 码API Key 不正确,请在第三方程序中使用“配置”->“常规”中的 api key:缺 API Key,请将“配置”->“常规”中的 api key 输入到第三方程序中:Prowl 的 API 密钥中止中止的条件中止无法完成的任务已中止,无法完成已中止,发现加密文件已中止,评分筛选器已命中 (%s)已中止,侦测到不需要的扩展名接受访问被拒绝动作根据过滤规则对下载任务执行操作RAR 文件中侦测到不需要的扩展名时的操作下载到加密的 RAR 文件时采取的操作侦测到不需要的扩展名时的操作操作添加添加文件添加 NZB添加 NZB 文件 添加定时任务添加服务器已添加 NZB管理文件夹高级影响分类发布时间全部所有文件保存到单个目录。本地网络地址以这些前缀开头 (通常为“192.168.1.”)允许负载均衡允许负载均衡,并对 IPv6 优化同时检索测试版本信息总是应用程序 token应用程序令牌 (必填)应用过滤器应用到所选项是否确定要重新启动 SABnzbd?是否确定要关闭 SABnzbd?是否确定?参数文章缓存限制文章 id至少至多音频音频评分身份认证失败,请检查用户名/密码。缺身份认证信息,请在第三方程序中输入“配置”->“常规”中的用户名/密码:自动续传当剩余空间低于该值时自动暂停。
单位为字节,可选添加 K、M、G、T 后缀。例如: "800M" 或 "8G"自动按 (平均) 发布时间排列项目。B返回备份Pushbullet 响应异常 (%s): %sPushover 响应异常 (%s): %s定时任务 %s 存在问题,时间为 %s:%syEnc 文章格式错误:%s带宽指向时停止刷新置底浏览CPU 型号在内存中缓存文章,以减轻硬盘访问压力。
单位为字节,可以选择加上 K、M、G 后缀。例如: "64M" 或 "128M"已缓存 %s 篇文章 (%s)取消无法更改 %s 的权限无法连接到服务器 %s [%s]无法创建 %s 文件夹 %s无法为 %s 创建备份文件无法创建目录 %s无法创建最终文件夹 %s无法为 %s 创建临时文件无法找到 email 模板:%s无法找到 web 模板: %s,正在尝试标准模板无法启动浏览器,可能未找到无法连接 SABHelper 服务无法读取 %s无法读取监视文件夹 %s无法发送,缺少必要的数据无法写入“历史记录”数据库,请检查访问权限!无法写入 INI 文件 %s分类分类证书验证更改未保存,改动将丢失。变更需要重启 SABnzbd 才会生效!全选下载前检查检查新版本正在检查检查间隔 (分钟,最小值为 15)。若使用“定时任务”则不会有效!选择皮肤。清理列表%s 清理失败。清除清除统计点击下面的“重复”按钮可开始测试点击可测试所输入的信息。关闭浏览器窗口/标签页 *不会* 导致 SABnzbd 关闭。逗号分隔的列表评论精简外观完成文件夹完成文件夹写入速度完成完成下载文件夹已完成文件夹 %s 位于 FAT 文件系统上,这样会有最大文件为 4GB 的限制。配置配置文件配置确认历史删除确认队列删除已确认连接 %s@%s 失败,消息=%s连接成功!连接失败!连接容器宽度损坏的 RAR 文件无法判断连接结果 (%s)无法解压 %s无法写入。请确保该目录有写入权限。当前定时任务自定义删*重复*每天每天文件夹“历史记录”数据库已损坏,已创建空数据库代替控制台日期排序日期格式每月特定一天年代解码器失败:内存不足%s 解码失败默认默认基本文件夹删除删除全部删除删除完成项删除失败项下载后删除从“历史”中删除所有已完成项?删除全部已下载文件?删除队列中全部项?从历史中删除所有失败项?删除 %s 失败!侦测重复下载侦测同季的重复剧集检测相同的 NZB 文件 (基于您的历史项目或 .nzb 备份文件夹中的文件)在剧目中检测相同的剧集 (基于您的历史项目,参照 "name/season/episode" 的规则)设备信息发送的目标设备设备信息发送的目标设备禁用配额管理禁用由于缺少 CERT 及 KEY 文件,已禁用 HTTPS舍弃队列为空或暂停时从 Usenet 服务器断开连接。清空队列时断开磁盘已满通知创建文件 %s 时磁盘出错磁盘空间已满磁盘已满! 强制暂停根据 SFV 文件进行额外验证。feed %s 无有效的身份认证凭据配额会每天、每周或每月重置吗?还没有 usenet 提供商r? 我们推荐试试 %s。下移下载下载完成下载目录下载失败下载所有 par2 文件下载失败 - 不在该服务器上下载文件夹读写速度下载可能会失败,只有 %s 块 (需要 %s) 可用已下载已下载,耗时 %s,平均速度 %sB/s正在下载下载列表双视图1双视图2重复的 NZB 文件如如 8 或 20*加密*错误:错误: %s错误: "%s" CRC 失败错误:文件太大文件系统不支持 (%s)*错误*: 路径过长 (%s)错误: 无法找到 "%s"错误: 写入出错 (%s)大约完成编辑编辑 NZB 详情否则暂停的条件Email任务完成 Email 通知Email 收件者Email 发送者邮件已发送!邮件模板文件夹发送 email 的目标电子邮箱地址。成功发送电子邮件紧急清空空 NZB 文件 %s发现空的 RSS 条目 (%s)启用启用 7zip启用日期排序启用过滤启用 Growl启用 HTTPS启用索引集成启用电影排序启用NotifyOSD启用 Prowl 通知启用 Pushbullet 通知启用 Pushover 通知启用基于 SFV 的检查启用 TV 排序启用 Unzip启用 Windows 通知启用 HTTPS 地址访问界面。启用文件夹重命名启用可减少内存占用。禁用可避免慢速任务拖慢队列进度。启用通知脚本启用配额管理启用递归解压启用路径末尾加上星号 * 可避免创建任务文件夹。输入 URL集 名集数集.名集_名错误"%s" 对 %s 运行 file_join 时出错"%s" 对集合 %s 执行 par2_repair 时出错出现错误 "%s",正对 %s 执行 rar_unpack 操作"%s" 对 %s 执行 unzip() 时出错%s 对集合 %s 执行 par2_repair 时出错错误 %s: 您需要提供有效的用户名与密码。创建 SSL key 及证书出错获取 TV 信息出错 (%s)导入 %s 出错无法加载 %s,侦测到损坏文件移除 %s 时出错移除工作目录出错 (%s)将 "%s" 重命名为 "%s" 出错加载 %s 出错,正在移除关闭系统时出错仅当发生错误时错误: 路径长度应不超过 %s。错误: 队列非空,无法变更文件夹。错误: 会话 Key 不正确错误: 需要会话 Key错误/警告全部示例执行自定义脚本退出 SABnzbd扩展名外部互联网访问额外的 PAR2 参数额外的历史记录列队列显示更多列正在提取...已过滤失败的任务 (移动到历史)失败无法登录服务器 %s创建失败 (%s)将 %s 移动到 %s 失败无法在邮件服务器上验证身份无法关闭数据库,参见日志无法关闭邮件连接为搜索关键词编译正则表达式失败: %s无法连接到邮件服务器系统休眠失败导入 %s 文件失败,来自 %s无法初始化 %s@%s,原因为: %s无法发起 TLS 连接移动文件失败重命名相似文件失败: %s 为 %s重命名失败: %s 为 %s预先检查后无法重新开始下载 NZB (%s)无法检索 %s 的 RSS: %s无法发送 Prowl 消息无法发送 Windows 通知无法发送 e-mail无法发送 pushbullet 信息无法发送 pushover 信息系统待机失败web 界面启动失败无法启动 web 界面: 失败于重复的 NZB 文件 "%s"失败tempfile.mkstemp 出错致命错误保存状态时遇到致命错误Assembler 出现致命错误Feed装取从 URL 装取 NZB正在装取正在装取 %s 块...正在装取额外块...文件 %s 为空,正在跳过文件扩展名包含要对加密 RAR 文件进行尝试的所有密码的文件。%s 文件合并失败HTTPS 证书文件名或路径。HTTPS 链文件名或路径。HTTPS Key 文件名或路径。服务器上无此文件文件集文件名过滤器过滤样本文件 (如视频样本)。首包含用户脚本的文件夹。包含用户定义的电子邮件模板的文件夹。要监视 .nzb 文件的文件夹。
会同时扫描 .zip .rar 及 .tar.gz 压缩文件中的 .nzb 文件。文件夹/路径文件夹email 身份认证所用的账号名称。email 身份认证所用的密码。供服务器使用: 确保名称与 Windows 系统兼容。对于不稳定的服务器,在失败后将会被忽略更长的时间强制强制断开连接强制下载正在强制断开连接格式: .nzb, .rar, .zip, .gz, .bz2论坛剩余 (临时)剩余空间频率周五来自剧目 SxxEyy来自 SxxEyy完整 API完整 Web 界面更详尽的帮助可以在我们的网站上找到GB常规生成新的 Key生成新的自签名证书和密钥。需要重启 SABnzbd!你可能会喜欢一些 Glitter 的(新)功能!转到 SABnzbd转到向导GrowlHTTP 与 HTTPS 端口不能相同HTTPS 证书HTTPS 链证书HTTPS KeyHTTPS 端口HTTPS 证书验证帮助帮助我们来本地化 SABnzbd !
您可以在这里来添加未被翻译的文字或者改进现有的翻译:电脑休眠隐藏编辑选项隐藏详情隐藏/显示已完成文件高历史最近十条历史记录历史数目限制按 shift 键可选择范围主页主页主机SABnzbd 应监听的主机。您希望在多久之后/什么时候暂停? (用英语作答!)本月能下载多少数据量 (K/M/G)*空闲**不完整*IONice 参数IPv6 地址IRC空闲若留空,则将监听 HTTPS 标准端口。如果您再次收到本错误信息,请尝试其他数字。
忽略样本文件忽略压缩包中的文件夹结构正在忽略重复 NZB "%s"位于若选择“暂停”,您将需要设置密码并手动续传对应任务。SABnzbd 重启后本画面将自动消失!分文件夹要从 usenet 下载您需要有一家提供商的访问权限。您的 ISP 可能会为您提供权限,但推荐您选用付费的高级提供商。feed 不兼容发现不兼容的队列文件,无法继续处理未完成文件夹NZB 文件 %s 不完整可合并的文件队列不完整RSS feed 描述不正确 "%s"参数不正确%s 值不正确: %s密码编码错误 %s降低 SSL 的加密难度以便获得更高的性能。索引 Categories / Groups评分文件的索引器 id (%s) 未找到索引可以在 NZB 文件中提供分类信息,SABnzbd 会尝试在以下分类中匹配。另外,您可以在 "索引 Categories / Groups" 中添加关键词来匹配更多的分类。使用逗号来分开关键词,关键词中可使用通配符。
你可以在维基中查看更多的相关信息。正在索引无效 NZB 文件 %s,正在跳过 (原因=%s, 行=%s)email 模板 %s 编码无效服务器地址无效。服务器信息无效%s 历史信息中 stage 日志无效反选问题建议您右击鼠标并将该链接加入书签以便在 SABnzbd 在后台运行时访问它。任务 "%s" 可能受加密保护,RAR 文件中存在相同名称的 RAR 文件。任务 "%s" 可能受加密保护:文件名 "%s" 中有 "password" 字符任务失败任务已完成合并文件正在合并将下载内容保留在额外文件夹语言末最新警告信息启动时启动浏览器启动 SABnzbd 时启动默认 web 浏览器。限速链接所有不需要扩展名的列表。例如: exe 或 exe, com下载后应删除的文件扩展名列表。
例如: nfo 或 nfo, sfv本地网段列表正在加载加载 %s 失败加载 %s 失败,错误 %s本地 IPv4 地址您的浏览器已禁用 LocalStorage (cookies)。界面设置将在您关闭浏览器后丢失!队列管理及历史数据库的存放位置。
仅当队列为空时可以修改。SABnzbd 日志文件的位置。
需要重启 SABnzbd 才能生效!存储完成且已完全处理的下载数据的位置。
可以通过用户定义分类额外调整。存储未处理下载数据的位置。
仅当队列为空时可以更改。存储 .nzb 文件的位置。日志文件夹登录注销日志失去与 SABnzbd 的连接..低大小写MB确保与 Windows 兼容已匹配最高速度最大线路速度各服务器重试的最多次数最多重试次数释义最小最小:启动 SSL 时,使用服务器自己的证书来验证身份。严格:验证并强制 hostname 一致。临时下载文件夹的最小剩余空间缺会话 key缺失文章适中周一月更多缩略图的减分比加分多影片 名称电影排序影片.名称影片_名称正在移动正在移动...多选操作多段标记NZB KeyNZB 已添加到队列名称域名服务器 / DNS 查询命名从不新版 %s 已发布,下载:新版本可用后Nice 参数无权访问未找到 email 模板不分文件夹由于验证失败,未进行后期处理未给定收件人,电子邮件未发出无结果未找到合适的身份验证方法无已启用的服务器均未选择“默认”分类。队列中未分配到服务器对应分类的任务不会开始下载。常规未匹配不可用磁盘空间不足以完成下载!未使用未选择任何内容!通知中心通知脚本通知已发送!通知脚本 "%s" 不存在通知屏显通知扫描 .nzb 文件的间隔时间。*可选* 账号密码*可选* 账号用户名关侦测到旧版队列,请使用“状态”→“修复”转换队列完成时失败时,尝试备用 NZB队列完成时您的 ISP 会在每月或每周的哪天 (1=星期一) 重置配额? (可选加上 hh:mm)只获取队列最顶端的文章只对外部访问要求登录仅对通过全部 PAR2 检查的任务执行后期处理。仅当使用远程 Growl 服务器时需要 (主机:端口)只为这些分类使用该服务器。打开信息 URL请打开“终端”窗口并输入下面一行命令 (例):打开完成文件夹可选可选补充 NZB可选身份验证密码。可选身份验证用户名。Growl 服务器可选密码可以选择指定文件名选项或将文件拖拽到本窗口!序号原始文件名孤立任务其他其他信息其他问题超出保留期*已暂停*传播延迟生效,等待 %s 分钟Par 验证失败:%s,但快速检查成功!参数分段号密码密码文件密码会以 ****** 显示,请重新输入有密码路径匹配匹配符释义暂停全部暂停后期处理过程中暂停下载暂停暂停 1 小时暂停 15 分钟暂停 3 小时暂停 30 分钟暂停 5 分钟暂停 6 小时暂停多少分钟?暂停...暂停高优先级任务暂停低优先级任务暂停常规优先级任务暂停后期处理已暂停开始后期处理时暂停下载,完成后续传。正在暂停重复 NZB "%s"线路速度的百分比完成下载权限个人 API keyProwl 的个人 API 密钥 (必填)注释请注意 0.0.0.0 主机名需要 IPv6 地址才能从外部访问请输入您的主 usenet 提供商的详细信息。端口SABnzbd 应监听的端口。后期处理失败:%s (%s)后期处理仅对经验证的任务进行后期处理后期处理后期处理已开始后期处理已中止 (%s)在文章发布时长尚不足该值时暂停下载文章。将任务优先级设为“强制”可跳过此延迟。预队列脚本将任务标记为失败的加入队列前执行的用户脚本预设请按 开始菜单键+R 并输入下面一行命令 (例):前避免负载均衡上一步优先级可能存在账号共享问题处理结果处理程序未启动!进度传播延迟Prowl公网 IPv4 地址清理清除已完成 NZB清除失败 NZB清除失败 NZB 并删除文件清空历史清空 NZB清空 NZB 并删除文件清理本页的 NZB 文件清空队列清空历史?清除队列?PushbulletPushoverPython 版本Python 脚本 "%s" 不具有执行 (+x) 权限队列将前十项加入队列队列已完成队列数目限制队列修复快速检查...快速检查退出配额剩余配额配额周期配额已耗尽,暂停下载修RAR 文件验证失败RAR 文件验证成功RSSRSS 检查间隔RSS Feed %s 为空执行 %s范围极少用到的选项。要获取其含义及解释,请点击“帮助”按钮访问 Wiki 页面。
在查看 Wiki 之前请不要更改这些选项,它们会有很严重的副作用。
括号中为默认值。立即读取全部 Feed读取 Feed读取 RSS feed读取所有 RSS feed关于该项请参阅 Wiki 帮助!刷新刷新频率刷新频率否决基于相对文件夹剩余记住我移除 NZB移除 NZB 并删除文件移除服务器移除已选文件移除已完成任务移除失败任务移除 %s 失败正在移除任务正在移除任务重命名修复修复失败,修复块不足 (缺 %s 块)正在修复修复失败,%s正在修复...重复测试替换文件夹名称中的空格替换文件夹名称中的点号将文件夹名称中的小数点替换成空格。将文件夹名称中的空格替换成下划线。报告需要需要 Prowl 账号需要 Pushbullet 账号需要 Pushover 账号需要分类重置立即重置配额重置时间重启重新启动 SABnzbd清除登录身份凭据设置并重新启动正在重新启动 SABnzbd...恢复默认值结果续传继续高优先级任务继续低优先级任务继续常规优先级任务继续后期处理恢复中保存期限重试重试所有全部重试重试所有失败任务重新尝试下载所有已失败任务重试“历史记录”中所有已失败任务?重试所有已失败任务?正在执行脚本正在执行脚本...正在执行用户脚本 %sS01E05 剧集文件夹S01E05 季度文件夹SABYenc 已禁用:未找到正确的版本!(找到 v%s,要求 v%s)SABYenc 模块... 未找到!要求 v%s - https://sabnzbd.org/sabyencSABnzbd %s 已启动SABnzbd 主机SABnzbd 密码SABnzbd 端口SABnzbd 快速上手向导SABnzbd 用户名SABnzbd 版本SABnzbd Web 服务器SABnzbd 侦测到致命错误:SABnzbd 关闭完成SABnzbd 以 %s 编码启动了,正常应该是 UTF-8。会导致下载文件夹中统一标准编码的文件和文件夹名称出现问题。SABnzbd 将在后台运行。SMTP 服务器SQL 命令执行失败,参见日志SSLSSL 加密算法周六保存保存更改已保存保存 %s 失败正在保存..扫描监视文件夹定时任务的服务器不存在 %s定时任务脚本脚本退出代码为 %s脚本返回退出代码 %s 及输出内容 "%s"脚本脚本文件夹搜索季数SABnzbd 与新闻组服务器之间的安全连接 (SSL) 以及 HTTPS 网站将会被加密,只不过,使用证书来验证服务器的身份却无法实现。要求 Python 2.7.9 或以上,OpenSSL 1.0.2 或以上,以及最新的本地 CA 证书存储。到服务器的安全连接安全选择 web 界面的语言。仅当您的服务商允许 SSL 连接时选择。选择发送发送 Group 命令发送 RSS 通知发回队列RSS feed 添加任务到队列时发送 email。磁盘已满、SABnzbd 暂停时发送 email。请求文章之前发送 group 命令。将通知发送到 Growl将通知发送到“通知中心”将通知发送到 NotifyOSD已将 %s 发送到队列以逗号来分开多个链接TV 排序服务器服务器 %s 需要用户/密码服务器 %s 使用的 HTTPS 证书不受信任%s 服务器使用了不受信任的证书 [%s]服务器 %s 将被忽略 %s 分钟服务器详情服务器地址服务器地址 "%s:%s" 无效。服务器地址必填服务器无法完成请求服务器描述服务器负载均衡服务器名无法解析服务器密码登录过程中服务器退出。服务器需要用户名与密码。服务器端错误 (服务器代码 %s);无法获取 %s (服务器 %s)服务器设置完成文件/文件夹的权限值。
八进制记法。例如: "755" 或 "777"设为您 ISP 的 email 出站服务器。设置完成!配额重置后是否自动续传下载?显示全部项显示编辑选项只显示失败项显示日志节目 名称节目名称文件夹显示活动连接显示详情显示界面节目.名称节目_名称正显示第 %s ~ %s 项结果,共 %s 项正显示一项结果关闭电脑关闭关闭 SABnzbd正在关闭捕捉到 %s 信号,正在保存并退出...尺寸部分文件的验证结果与 "%s" 不符部分服务器在下载失败时可提供备用 NZB 文件。抱歉,无法理解您的输入。请重试。排序排序字串按发布时间排列按发布时间排列 (最新→最早)按发布时间排列 (最早→最新)按发布时间排序 最新→最早按发布时间排序 最早→最新按名称排列 (A→Z)按名称排列 (Z→A)按名称排序 A→Z按名称排序 Z→A按尺寸排列 (最大→最小)按尺寸排列 (最小→最大)按尺寸排序 最大→最小按尺寸排序 最小→最大排序来源垃圾特殊速度限速安装支持多核心的 Par2 以便加快修复速度,支持多平台。限速电脑待机启动向导正在开始修复启动/关闭状态状态与界面选项停止正在停止...严格主题提交已提交。感谢!周日支持该项目,捐助!下载器疑似错误参数系统负载系统文件夹系统性能 (Pystone)TEXT*太大*标签化外观
(分别显示队列与历史记录)任务临时文件夹临时下载文件夹测试邮件测试通知测试服务器正在测试服务器详细情况...“修复”按钮可重启 SABnzbd 并执行完整的
队列内容重建操作,同时将保留已下载的文件。
队列的顺序会有所改变。usenet 自动下载工具需要勾选 feed 名称旁边的复选框才能启用并自动检查新项。
添加 feed 后,它将只选取新项目,而不选取已经处于 RSS feed 当中的项,除非您按“强制下载”。主机名未设置。提供商所允许的连接数服务器未正确回复 helo 问候未设置连接。请设置至少一个连接。下载目录中存在孤立任务。
您可以选择删除任务 (及其文件) 或将它们发回队列。这个密钥用来向服务器表明身份。查看您在索引网站上的个人档案。该 key 将允许第三方程序将 NZB 添加到 SABnzbd 中。该 key 将授予第三方程序 SABnzbd 的完整权限。本月当需要时下载所有的 par2 文件以避免多次运行修复。该服务器不允许在该端口使用 SSL本周这将在您的鼠标指针处于队列上方时阻止内容刷新。这将重新启动 SABnzbd。
如果您认为程序存在稳定性问题,请使用该项。
重启前将暂停下载,之后将继续下载。这将发送一封测试邮件到您的账号当中。周四超时超时: 请尝试启用 SSL 或连接其他端口。剩余时间超时标题标题关键词To: %s From: %s Date: %s Subject: SABnzbd 报告磁盘已满 Hi, 由于磁盘几乎已满,SABnzbd 已停止下载。 请腾出空间再手动让 SABnzbd 续传。 今天切换新增 NZB磁盘空间过低,强制 *暂停*服务器 %s 连接数过多连接数过多,请先暂停下载或稍后再试置顶顶部菜单切换总计疑难解决请尝试我们的新皮肤“Glitter”! 为桌面及移动设备优化的全新设计。请到“配置”->“常规”更改皮肤。在实际下载之前尝试预测可以成功下载的完整程度 (会减慢下载进度!)正在尝试 7zip,密码 "%s"正在尝试基于 RAR 的验证正在尝试 SFV 验证正在尝试从 %s 装取 NZB正在尝试设置不存在的服务器 %s 的状态正在尝试 unrar,使用密码 "%s"周二调节类型解此处不允许使用 UNC 路径 "%s"不需要URL 装取失败; %s*URLGRABBER 已崩溃*检测到 UUencode,但是仅有 yEnc 编码受支持 [%s]绑定端口 %s 在 %s 上失败。其它的程序正在使用此端口或者说 SABnzbd 正在运行。未授权访问解封未定义服务器!解码 %s 时发生未知错误未知的 SSL 协议:尝试禁用 SSL 或者连接不同的端口。未知操作: %s邮件服务器出现未知身份验证错误解压解压压缩包内的压缩包 (rar, zip, 7z)。解压嵌套层级过深 [%s]已解压 %s 个文件/文件夹,耗时 %s正在解压解压失败,%s解压失败,CRC 错误解压失败,压缩文件需要密码解压失败,文件太大文件系统不支持 (FAT?)解压失败,路径过长解压失败,参见日志解压失败,找不到 %s解压失败,写入出错或磁盘已满?%s 中有失败的登陆请求不可用的 NZB 文件无法使用的 RAR 文件rar 文件中出现不需要的扩展名 %s不需要的扩展名上移有更新可用!上传上传 NZB上传: .nzb .rar .zip .gz, .bz2正在上传启动时间使用全局界面设置后期处理过程中使用临时名称。若您的系统无法正常处理请禁用。用于在 NZB 进入队列前执行。已用缓存如果新闻服务器有多个 IPv4/IPv6 地址将非常有用用户文件夹用户 key用户密钥 (必填)用户已登录用户已在 web 界面登录用户脚本可将任务标记为失败用户名值成功使用 SFV 文件验证当用 HTTPS 方式连接索引和RSS源时验证证书。正在验证正在验证...版本非常低视频视频评分查看脚本日志病毒/垃圾*等待* %s 秒警告:警告:"%s" 任务已终止,因其包含加密 RAR 文件 (已尝试所有的密码,如果提供了的话)*警告*: 任务“%s”已中止,由于评分过低 (%s)*警告*: RAR 文件“%s”中出现不需要的扩展名。不需要的文件名为 %s 警告:"%s" 任务已暂停,因其包含加密 RAR 文件 (已尝试所有的密码,如果提供了的话)*警告*: 任务“%s”已暂停,由于评分过低 (%s)等待警告警告: LOCALHOST 太含糊,请使用数字 IP 地址。警告信息监视文件夹监视文件夹扫描速度Web 界面周三每周检查 SABnzbd 的新版本。时间下载时若发现缺失数据过多,则中止对应任务用户脚本返回非零的退出代码时,对应的任务将被标记为失败。每当您的 IP 地址发生变化,或当 SABnzbd 重启,登录会话将自动过期。SABnzbd 应占用的线路速度的百分比,如 50应该执行哪个脚本来发出通知?我们应该说是谁发送了这封 email?WikiWindows写入速度X年年-月文件夹您可以设定非本地网络的访问权限。要求定义本地网络列表。您必须启用 JavaScript 才能使用 Plush 模板!设置带宽限制前,您必须设置最大带宽值您的 UNRAR 程序版本为 %s,我们建议使用 %s 或更高版本。
您自己的 Pushbullet API key (必填)[%s] "%s" 合并文件时出错[%s] "%s" 解压 RAR 文件时出错[%s] 已合并 %s 个文件[%s] 无 par2 集合[%s] PAR2 收到的选项不正确,请检查您的“配置”->“参数”设置[%s] 快速检查 OK[%s] 基于 RAR 的验证失败: %s[%s] 已修复,耗时 %s[%s] 验证耗时 %s,所有文件均完好无损[%s] 验证耗时 %s,需要修复_yenc 模块... *未* 找到!篇文章音频大小写已调整清除天天天禁用服务器已减分启用服务器文件小时小时小时关键词剩余分钟手动分钟分钟分钟未安装/关开或或更少页par2 可执行程序... *未* 找到!有密码秒秒查看日志文件垃圾text未知unrar 可执行程序... *未* 找到unzip 可执行程序... *未* 找到!视频周SABnzbd-2.3.2/po/email/da.po0000644000000000000000000001307213217005051013555 0ustar 00000000000000# Danish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: shypike \n" "Language-Team: Danish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## Standard Email skabelon til SABnzbd\n" "## Dette er en Cheetah skabelon\n" "## Dokumentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Linjeskift og blanktegn er betydelig!\n" "##\n" "## Disse er e-mail-headerne \n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd har " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Efter dette kommer body, den tomme linje kræves!\n" "\n" "Hej,\n" "\n" "SABnzbd har hentet \"$name\" \n" "\n" "SABnzbd kunne ikke hente \"$name\" \n" "\n" "Færdig kl. $end_time\n" "Hentet $size\n" "\n" "Resultat af job:\n" "\n" "Etape $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output fra bruger script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## RSS Email skabelon til SABnzbd\n" "## Dette er Cheetah skabelon\n" "## Dokumentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Linjeskift og blanktegn er betydelig!\n" "##\n" "## Dette er email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd har tilføjet $antal jobs til køen\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Efter dette kommer body, den tomme linje kræves!\n" "\n" "Hej,\n" "\n" "SABnzbd har tilføjet $antal job(s) til køen.\n" "De er fra RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Farvel\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Dårlig URL Fetch E-mail skabelon for SABnzbd\n" "## Dette er en Cheetah skabelon\n" "## Dokumentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Linjeskift og blanktegn er betydelig!\n" "##\n" "## Dette er email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd kunne ikke hente en NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Efter dette kommer body, den tomme linje kræves!\n" "\n" "Hej,\n" "\n" "SABnzbd kunne ikke hente NZB fra $url.\n" "Fejl meddelelsen er: $msg\n" "\n" "Farvel\n" SABnzbd-2.3.2/po/email/de.po0000644000000000000000000001357713217005051013573 0ustar 00000000000000# German translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Thomas Lucke (Lucky) \n" "Language-Team: German \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "#encoding UTF-8\n" "## Translation by Severin Heiniger\n" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd Auftrag " "$name \n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd hat \"$name\" heruntergeladen\n" "\n" "SABnzbd konnte \"$name\" nicht herunterladen\n" "\n" "Fertiggestellt: $end_time\n" "Heruntergeladen: $size\n" "\n" "Ergebnis des Auftrages:\n" "\n" "Stufe $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Ausgabe des Benutzerskripts \"$script\" (beendet mit Code $script_ret):\n" "$script_output\n" "\n" "\n" "Viel Spass!\n" "\n" "Entschuldigung!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd hat $amount Aufträge zur Warteschlange hinzugefügt\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hallo,\n" "\n" "SABnzbd hat $amount Aufträge zur Warteschlange hinzugefügt.\n" "Sie stammen vom RSS-Feed \"$feed\".\n" "\n" " $job \n" "\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "## Translation by Thomas Lucke (Lucky)\n" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd konnte eine NZB-Datei nicht herunterladen\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hallo,\n" "\n" "SABnzbd konnte die NZB-Datei von $url nicht herrunterladen.\n" "Die Fehlermeldung war: $msg\n" SABnzbd-2.3.2/po/email/en.po0000644000000000000000000000002313217004754013574 0ustar 00000000000000# Dummy en.po file SABnzbd-2.3.2/po/email/es.po0000644000000000000000000001355113217005051013602 0ustar 00000000000000# Spanish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: shypike \n" "Language-Team: Spanish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## Plantilla de correo predeterminada para SABnzbd\n" "## This a Cheetah template\n" "## Documentación: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## !Los saltos de línea y espacios en blanco son significativos¡\n" "##\n" "## Cabeceras de correo electrónico\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## !Después de esto viene el cuerpo del mensaje, la línea en blanco es " "necesaria!\n" "\n" "Hola,\n" "\n" "SABnzbd he bajado \"$name\" \n" "\n" "SABnzbd fallo en bajar \"$name\" \n" "\n" "Terminado a las $end_time\n" "$size bajado\n" "\n" "Resultado de la transferencia:\n" "\n" "Etapa $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Producción desde el script de usuario \"$script\" (Exit code = " "$script_ret):\n" "$script_output\n" "\n" "\n" "Que lo disfrutes!\n" "\n" "Perdon!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## Plantilla de correo RSS para SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## !Los saltos de línea y espacios en blanco son significativos¡\n" "##\n" "## Cabeceras de correo electrónico\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd he añadido $amount transferencia(s) a la cola\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## !Después de esto viene el cuerpo del mensaje, la línea en blanco es " "necesaria!\n" "\n" "Hola,\n" "\n" "SABnzbd he añadido $amount transferencia(s) a la cola.\n" "Originaron desde el RSS \"$feed\".\n" "\n" "$job \n" "\n" "\n" "Adios\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Plantilla de correo para URLs incorrectas de SABnzbd\n" "## Esta es una plantilla Cheetah\n" "## Documentación: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Líneas nuevas y espacios en blanco IMPORTAN!\n" "##\n" "## Estas son las cabeceras del email\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd ha encontrado un error al recuperar un NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hola,\n" "\n" "SABnzbd ha encontrado un error al descargar un NZB desde $url.\n" "El error ha sido: $msg\n" "\n" "Un saludo\n" SABnzbd-2.3.2/po/email/fi.po0000644000000000000000000001352413217005051013571 0ustar 00000000000000# Finnish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Matti Ylönen \n" "Language-Team: Finnish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## Oletus sähköpostipohja SABnzbd:lle\n" "## Tämä on Cheetah pohja\n" "## Dokumentaatio: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Rivinvaihdot ja välilyönnit ovat merkitseviä!\n" "##\n" "## Nämä ovat otsaketiedot. Rivien ensimmäisiä sanoja ei saa vaihtaa!\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd on työssä $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Tämän jälkeen tulee viestin runko, ensimmäinen rivinvaihto on " "pakollinen!\n" "\n" "Hei,\n" "\n" "SABnzbd on ladannut \"$name\" \n" "\n" "SABnzbd on epäonnistunut \"$name\" latauksessa\n" "\n" "Valmistui $end_time\n" "Ladattu $size\n" "\n" "Työn lopputulos:\n" "\n" "Tila $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Käyttäjän skriptin tuloste \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Nauti!\n" "\n" "Pahoittelut!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## RSS sähköpostipohja SABnzbd:lle\n" "## Tämä on Cheetah pohja\n" "## Dokumentaatio: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Rivinvaihdot ja välilyönnit ovat merkitseviä!\n" "##\n" "## Nämä ovat otsaketiedot. Rivien ensimmäisiä sanoja ei saa vaihtaa!\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd on lisännyt $amount työtä jonoon\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Tämän jälkeen tulee viestin runko, ensimmäinen rivinvaihto on " "pakollinen!\n" "\n" "Hei,\n" "\n" "SABnzbd on lisännyt $amount työtä jonoon.\n" "Ne ovat RSS syötteestä \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Heippa\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Virheellisen URL-noudon sähköpostin pohja SABnzbd ohjelmalle\n" "## Tämä on Cheetah pohja\n" "## Dokumentaatio: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Rivinvaihdot ja välilyönnit ovat merkitseviä!\n" "##\n" "## Tässä on sähköpostin otsikkotiedot\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd ei voinut hakea NZB tiedostoa\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Tämän jälkeen tulee viestin sisältö, tyhjä rivi on pakollinen!\n" "\n" "Hei,\n" "\n" "SABnzbd ei voinut hakea NZB tiedostoa osoitteesta $url.\n" "Virheviesti: $msg\n" SABnzbd-2.3.2/po/email/fr.po0000644000000000000000000001341413217005051013600 0ustar 00000000000000# French translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Fox Ace \n" "Language-Team: French \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "#encoding UTF-8\n" "##\n" "## Template Email pour SABnzbd\n" "## Ceci est un template Cheetah\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Les retours à la ligne et les espaces sont importants !\n" "##\n" "## Entêtes de l'email\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd SuccèsEchec " "du téléchargement $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Après cela vient le contenu, la ligne vide est nécessaire! \n" "\n" "Bonjour,\n" "\n" "SABnzbd a téléchargé avec succès \"$name\" \n" "\n" "SABnzbd a téléchargé sans succès \"$name\" \n" "\n" "Terminé à $end_time\n" "Téléchargé $size\n" "\n" "Résultat du téléchargement :\n" "\n" "Etape $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Sortie du script utilisateur \"$script\" (Code Retour = $script_ret):\n" "$script_output\n" "\n" "\n" "A bientôt !\n" "\n" "Désolé !\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## Template Email pour SABnzbd\n" "## Ceci est un template Cheetah\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Les retours à la ligne et les espaces sont importants !\n" "##\n" "## Entêtes de l'email\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd a ajouté $amount fichier(s) à la file d'attente\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Après cela vient le contenu, la ligne vide est nécessaire!\n" "\n" "Bonjour,\n" "\n" "SABnzbd a ajouté $amount fichier(s) à la file d'attente.\n" "Ils proviennent du Flux RSS \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Au Revoir\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" SABnzbd-2.3.2/po/email/he.po0000644000000000000000000001351013217005051013562 0ustar 00000000000000# Hebrew translation for sabnzbd # Copyright (c) 2017 Rosetta Contributors and Canonical Ltd 2017 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2017. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2017-08-01 16:45+0000\n" "Last-Translator: ION IL \n" "Language-Team: Hebrew \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-08-02 06:03+0000\n" "X-Generator: Launchpad (build 18441)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## SABnzbd תבנית דוא\"ל ברירת מחדל עבור\n" "## זאת תבנית ברדלס\n" "## http://sabnzbd.wikidot.com/email-templates :תיעוד\n" "##\n" "## !שורות חדשות ורווחים לבנים הם משמעותיים\n" "##\n" "## אלו כותרות הדוא\"ל\n" "$to :אל\n" "$from :מאת\n" "תאריך: $date\n" " $name יש עבודה אשר " "SABnzbd-נושא: ל\n" "## !אחרי זה בא הגוף, השורה הריקה דרושה\n" "\n" ",היי\n" "\n" "SABnzbd הוריד את \"$name\" \n" "\n" "SABnzbd נכשל להוריד את \"$name\" \n" "\n" "הסתיים ב-$end_time\n" "הורדו $size\n" "\n" ":תוצאות העבודה\n" "\n" "שלב $stage \n" "\n" " $result \n" "\n" "\n" "\n" ":(קוד יציאה = $script_ret) \"$script\" פלט מתסריט משתמש\n" "$script_output\n" "\n" "\n" "!תהנה\n" "\n" "!סליחה\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## SABnzbd עבור RSS תבנית דוא\"ל\n" "## זאת תבנית ברדלס\n" "## http://sabnzbd.wikidot.com/email-templates :תיעוד\n" "##\n" "## !שורות חדשות ורווחים לבנים הם משמעותיים\n" "##\n" "## אלו כותרות הדוא\"ל\n" "$to :אל\n" "$from :מאת\n" "תאריך: $date\n" "הוסיף $amount עבודות לתור SABnzbd :נושא\n" "## !אחרי זה בא הגוף, השורה הריקה דרושה\n" "\n" ",היי\n" "\n" ".הוסיף $amount עבודות לתור SABnzbd\n" ".\"$feed\" בשם RSS הם מהזנת\n" "\n" " $job \n" "\n" "\n" "ביי\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## SABnzbd רעה עבור URL תבנית דוא\"ל של משיכת\n" "## זאת תבנית ברדלס\n" "## http://sabnzbd.wikidot.com/email-templates :תיעוד\n" "##\n" "## !שורות חדשות ורווחים לבנים הם משמעותיים\n" "##\n" "## אלו כותרות הדוא\"ל\n" "$to :אל\n" "$from :מאת\n" "תאריך: $date\n" "NZB נכשל במשיכת SABnzbd :נושא\n" "## !אחרי זה בא הגוף, השורה הריקה דרושה\n" "\n" ",היי\n" "\n" ".$url מתוך NZB-נכשל לאחזר את ה SABnzbd\n" "הודעת השגיאה הייתה: $msg\n" "\n" "ביי\n" SABnzbd-2.3.2/po/email/nb.po0000644000000000000000000001330413217005051013566 0ustar 00000000000000# Norwegian Bokmal translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: Norwegian Bokmal \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "#encoding UTF-8\n" "## Translation by ProtX\n" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd har " "jobb $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hei,\n" "\n" "SABnzbd har lastet ned \"$name\" \n" "\n" "SABnzbd mislyktes med å laste ned \"$name\" \n" "\n" "Ferdig $end_time\n" "Nedlastet $size\n" "\n" "Resultat av jobben:\n" "\n" "Steg $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Utskrift fra brukerskript \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Gratulerer!\n" "\n" "Synd!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd har lagt $amount jobber til køen\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Etter dette kommer meldingen, den tomme linjen er nødvendig!\n" "\n" "Hei,\n" "\n" "SABnzbd har lagt $amount jobb(er) til køen.\n" "Disse er fra RSS feeden \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Hade\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd ikke klarte å hente en NZB fil\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Etter dette kommer meldingen, den tomme linjen er nødvendig!\n" "\n" "Hei,\n" "\n" "SABnzbd klarte ikke å hente NZB fra $url.\n" "Feilmeldingen var: $msg\n" "\n" "Hade\n" SABnzbd-2.3.2/po/email/nl.po0000644000000000000000000001331613217005051013603 0ustar 00000000000000# Dutch translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: shypike \n" "Language-Team: Dutch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## Standaard Email sjabloon voor SABnzbd\n" "## Dit is een Cheetah sjabloon\n" "## Documentatie: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Lege regels en witruimte zijn belangrijk!\n" "##\n" "## Dit zijn de email koppen\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd: opdracht $name is \n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Hier onder volgt de hoofdtekst, de lege regel is noodzakelijk!\n" "\n" "Hallo,\n" "\n" "SABnzbd heeft \"$name\" gedownload\n" "\n" "SABnzbd is niet geslaagd in het downloaden van \"$name\" \n" "\n" "Klaar om $end_time\n" "Hoeveelheid gedownload $size\n" "\n" "Resultaat van de opdracht:\n" "\n" "Fase $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Bericht van het script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Veel plezier!\n" "\n" "Sorry!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## RSS Email sjabloon voor SABnzbd\n" "## Dit is een Cheetah sjabloon\n" "## Documentatie: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Lege regels en spaties zijn belangrijk!\n" "##\n" "## Dit zijn de email koppen\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd heeft $amount opdrachten aan de wachtrij toegevoegd\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Hierna komt de inhoud, de lege regel is benodigd!\n" "\n" "Hallo,\n" "\n" "SABnzbd heeft $amount opdrachten aan de wachtrij toegevoegd.\n" "Ze komen van de RSS bron \"$feed\".\n" "\n" " $job \n" "\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Ongeldige URL Ophaal Email sjabloon voor SABnzbd\n" "## Dit is een Cheetah sjabloon\n" "## Documentatie: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Lege regels en spaties zijn belangrijk!\n" "##\n" "## Dit zijn de email koppen\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: Ophalen van NZB door SABnzbd is mislukt\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Hierna komt het bericht, de lege regel is noodzakelijk!\n" "\n" "Hi,\n" "\n" "Het is SABnzbd niet gelukt om een NZB bestand op te halen van $url.\n" "De foutmelding was $msg\n" "\n" "Sorry\n" SABnzbd-2.3.2/po/email/pl.po0000644000000000000000000001331413217005051013603 0ustar 00000000000000# Polish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Tomasz 'Zen' Napierala \n" "Language-Team: Polish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## Domyślny szablon maila w SABnzbd\n" "## To jest szablon Cheetah\n" "## Dokumentacja: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Znak nowego wiersza i spacji ma znaczenie!\n" "##\n" "## To są nagłowki maila\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd zadanie $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Następnie treść maila, wymagana jest pusta linia!\n" "\n" "Cześć,\n" "\n" "SABnzbd pobrał \"$name\" \n" "\n" "SABnzbd nie pobrał \"$name\" \n" "\n" "Zakończono o $end_time\n" "Pobrano $size\n" "\n" "Rezultat zadania:\n" "\n" "Etap $stage \n" "\n" "$result \n" "\n" "\n" "\n" "Odpowiedź od skryptu \"$script\" (kod wyjścia = $script_ret):\n" "$script_output\n" "\n" "\n" "Baw się dobrze!\n" "\n" "Przykro mi!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## Szablon wiadomości RSS dla SABnzbd\n" "## To jest szablon Cheetah\n" "## Dokumentacja: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Znak nowego wiersza i spacji ma znaczenie!\n" "##\n" "## To są nagłowki maila\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd dodał $amount zadań/zadania do kolejki\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Następnie treść maila, wymagana jest pusta linia!\n" "\n" "Cześć,\n" "\n" "SABnzbd dodał $amount zadanie/zadań do kolejki.\n" "Pochodzą one z wiadomości RSS \"$feed\".\n" "\n" "$job \n" "\n" "\n" "Nara\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Szablon wiadomości błędnego pobierania URL SABnzbd\n" "## To jest szablon Cheetah\n" "## Dokumentacja: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Znaki nowego wiersza i białe znaki mają znaczenie!\n" "##\n" "## To są nagłówki wiadomości\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd nie udało się pobrać pliku NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Po tym następuje treść. Pusty wiersz jest wymagany!\n" "\n" "Cześć,\n" "\n" "SABnzbd nie udało się pobrać pliku NZB z $url.\n" "Komunikat błędu: $msg\n" "\n" "Do usłyszenia.\n" SABnzbd-2.3.2/po/email/pt_BR.po0000644000000000000000000001356413217005051014205 0ustar 00000000000000# Brazilian Portuguese translation for sabnzbd # Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2012. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: lrrosa \n" "Language-Team: Brazilian Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## Template padrão de e-mail para SABnzbd\n" "## Este é um template Cheetah\n" "## Documentação: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Novas linhas e espaços em branco são significativos!\n" "##\n" "## Estes são os cabeçalhos de e-mail\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd a " "tarefa $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Depois daqui vem o corpo. A linha vazia é necessária!\n" "\n" "Olá,\n" "\n" "SABnzbd baixou \"$name\" \n" "\n" "SABnzbd falhou no download de \"$name\" \n" "\n" "Completado em $end_time\n" "Baixados $size\n" "\n" "Resultados da tarefa:\n" "\n" "Etapa $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Retorno do script de usuário \"$script\" (Código de retorno = $script_ret):\n" "$script_output\n" "\n" "\n" "Aproveite!\n" "\n" "Lamento!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## Template de e-mail RSS para SABnzbd\n" "## Este é um template Cheetah\n" "## Documentação: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Novas linhas e espaços em branco são significativos!\n" "##\n" "## Estes são os cabeçalhos de e-mail\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd adicionou $amount à fila\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Depois daqui vem o corpo. A linha vazia é necessária!\n" "\n" "Olá,\n" "\n" "SABnzbd adicionou $amount à fila.\n" "Elas são do feed RSS \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Tchau!\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Template de e-mail de busca em URL ruim para SABnzbd\n" "## Este é um template Cheetah\n" "## Documentação: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Novas linhas e espaços em branco são significativos!\n" "##\n" "## Estes são os cabeçalhos de e-mail\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd falhou ao buscar um NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Depois daqui vem o corpo. A linha vazia é necessária!\n" "\n" "Olá,\n" "\n" "SABnzbd não conseguiu obter o NZB de $url.\n" "A mensagem de erro foi: $msg\n" "\n" "Tchau!\n" SABnzbd-2.3.2/po/email/ro.po0000644000000000000000000001345013217005051013611 0ustar 00000000000000# Romanian translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: nicusor \n" "Language-Team: Romanian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## Șablon Email Original pentru SABnzbd\n" "## Acesta este un Șablon Cheetah\n" "## Documentație: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "##Rândurile noi și caracterele spațiu sunt importante!\n" "##\n" "## Acestea sunt antetele email\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd \n" "SABnzbd a descărcat \"$name\" \n" "\n" "SABnzbd nu a reuşit să descarce \"$name\" \n" "\n" "Terminat la $end_time\n" "Mărime $size\n" "\n" "Rezultatele sarcinii:\n" "\n" "Stagiu $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Rezultatul script-ului utilizatorului \"$script\" (Exit code = " "$script_ret):\n" "$script_output\n" "\n" "\n" "Bucuraţi-vă!\n" "\n" "Ne pare rau!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "## Şablon Email RSS pentru SABnzbd\n" "## Acesta este un şablon Cheetah \n" "## Documentaţie: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Rândurile noi și caracterele spațiu sunt importante!\n" "##\n" "## Acestea sunt antetele email\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd a adăugat $amount sarcini în coadă\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## După acesta urmează conţinutul, este necesar o linie goală!\n" "\n" "Salut,\n" "\n" "SABnzbd a adăugat $amount sarcină(e) în coadă.\n" "Ele sunt din fluxuri RSS \"$feed\".\n" "\n" " $job \n" "\n" "\n" "La revedere !\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Adresă URL Greşită şablon Email pentru SABnybd \n" "## Acesta este un şablon Cheetah\n" "## Documentaţie : http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Liniile noi şi spaţiile sunt importante!\n" "##\n" "## Acestea sunt headerele email\n" "Către: $to\n" "De la: $from\n" "Dată: $date\n" "Subiect: SABnzbd nu a reuşit să descarce un NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## După aceasta urmează corpul email, linia goală e necesară !\n" "\n" "Salut,\n" "\n" "SABnzbd nu a putut descărca NZB-ul de la adresa $url.\n" "Mesajul de eroare a fost: $msg\n" "\n" "La revedere!\n" SABnzbd-2.3.2/po/email/ru.po0000644000000000000000000001535713217005051013627 0ustar 00000000000000# Russian translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Pavel Maryanov \n" "Language-Team: Russian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## Стандартный шаблон сообщения электронной почты\n" "## Это шаблон Cheetah\n" "## Документация: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Новые строки и пробелы имеют значение!\n" "##\n" "## Это заголовки электронной почты\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd: задание $name \n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Теперь следует тело сообщения. Пустая строка является обязательной!\n" "\n" "Привет.\n" "\n" "Системой SABnzbd загружено задание «$name» \n" "\n" "Системе SABnzbd не удалось загрузить «$name» \n" "\n" "Время окончания загрузки: $end_time\n" "Загруженный размер: $size\n" "\n" "Результаты задания:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Результат выполнения сценария «$script» (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Удачи!\n" "\n" "Сожалеем.\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## Шаблон RSS для электронной почты\n" "## Это шаблон Cheetah\n" "## Документация: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Новые строки и пробелы имеют значение!\n" "##\n" "## Это заголовки электронной почты\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: В очередь загрузки SABnzbd добавлены задания: $amount \n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Теперь следует тело сообщения. Пустая строка является обязательной!\n" "\n" "Привет.\n" "\n" "В очередь загрузки SABnzbd были добавлены задания: $amount.\n" "Они были получены из RSS-ленты «$feed».\n" "\n" " $job \n" "\n" "\n" "До свидания\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Шаблон электронной почты для излечения неверного URL-адреса\n" "## Это шаблон Cheetah\n" "## Документация: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Новые строки и пробелы имеют значение!\n" "##\n" "## Это заголовки электронной почты\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: Службе SABnzbd не удалось загрузить NZB-файл\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## Теперь следует тело сообщения. Пустая строка является обязательной!\n" "\n" "Привет.\n" "\n" "Службе SABnzbd не удалось загрузить NZB-файл по адресу $url.\n" "Сообщение об ошибке: $msg\n" "\n" "Конец сообщения\n" SABnzbd-2.3.2/po/email/SABemail.pot0000644000000000000000000000564613217004754015013 0ustar 00000000000000# # SABnzbd Translation Template file EMAIL # Copyright 2011-2017 The SABnzbd-Team # team@sabnzbd.org # msgid "" msgstr "" "Project-Id-Version: SABnzbd-2.2.0-develop\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: shypike@sabnzbd.org\n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ASCII\n" "Content-Transfer-Encoding: 7bit\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" SABnzbd-2.3.2/po/email/sr.po0000644000000000000000000001470713217005051013623 0ustar 00000000000000# Serbian translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # Мирослав Николић , 2011. msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2017-06-24 19:51+0000\n" "Last-Translator: Safihre \n" "Language-Team: Launchpad Serbian Translators\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-27 06:00+0000\n" "X-Generator: Launchpad (build 18416)\n" "Language: sr\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## Основни шаблон ел. поште за САБнзбд\n" "## Ово је Гепард шаблон\n" "## Документација: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Нови редови и размаци су важни!\n" "##\n" "## Ово су заглавља ел. поште\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: САБнзбд је " "посао „$name“\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## После тога долази разрада, празни редови су потребни!\n" "\n" "Здраво,\n" "\n" "САБнзбд је преузео „$name“ \n" "\n" "САБнзбд није успео да преузме „$name“ \n" "\n" "Завршено је у $end_time\n" "Преузето је $size\n" "\\n\n" "Резултат рада:\n" "\n" "Фаза $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Излаз корисничке скрипте „$script“ (Шифра излаза = $script_ret):\n" "$script_output\n" "\n" "\n" "Уживајте!\n" "\n" "Жао ми је!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## РСС шаблон ел. поште за САБнзбд\n" "## Ово је Гепард шаблон\n" "## Документација: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Нови редови и размаци су важни!\n" "##\n" "## Ово су заглавља ел. поште\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject САБнзбд је додао $amount посла у ред\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## После тога долази разрада, празни редови су потребни!\n" "\n" "Здраво,\n" "\n" "САБнзбд је додао $amount посао(ла) у ред.\n" "Долазе са РСС довода „$feed“.\n" "\n" " $job \n" "\n" "\n" "Поздрав\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Шаблон ел. поште лошег набављања адресе за САБнзбд\n" "## Ово је Гепард шаблон\n" "## Документација: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Нови редови и размаци су важни!\n" "##\n" "## Ово су заглавља ел. поште\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: САБнзбд није успео да преузме НЗБ\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## После тога долази разрада, празни редови су потребни!\n" "\n" "Здраво,\n" "\n" "САБнзбд није успео да преузме НЗБ са „$url“.\n" "Порука грешке је: $msg\n" "\n" "Поздрав\n" SABnzbd-2.3.2/po/email/sv.po0000644000000000000000000001332713217005051013624 0ustar 00000000000000# Swedish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2017-06-24 19:50+0000\n" "Last-Translator: Safihre \n" "Language-Team: Swedish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-27 06:00+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "## Translation by Andreas Lindberg andypandyswe@gmail.com\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hej,\n" "\n" "SABnzbd har laddat ned \"$name\" \n" "\n" "SABnzbd misslyckades med att ladda ned \"$name\" \n" "\n" "Färdig $end_time\n" "Nedladdat $size\n" "\n" "Resultat:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Utmatning från användarskript \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Lycka till!\n" "\n" "Beklagar!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd har lagt till $amount jobb i kön\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hej,\n" "\n" "SABnzbd har lagt till $amount jobb i kön.\n" "De kommer från RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Hej då\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd misslyckades med att hämta en NZB -fil\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hej,\n" "\n" "SABnzbd har misslyckats med att hämta NZB -filen från $url.\n" "Felmeddelandet lyder: $msg\n" "\n" "Hej då\n" SABnzbd-2.3.2/po/email/zh_CN.po0000644000000000000000000001303313217005051014167 0ustar 00000000000000# Chinese (Simplified) translation for sabnzbd # Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2012. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2015-10-24 11:05+0000\n" "Last-Translator: shypike \n" "Language-Team: Chinese (Simplified) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n" "X-Generator: Launchpad (build 18416)\n" #: email/email.tmpl:1 msgid "" "##\n" "## Default Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has " "job $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has downloaded \"$name\" \n" "\n" "SABnzbd has failed to download \"$name\" \n" "\n" "Finished at $end_time\n" "Downloaded $size\n" "\n" "Results of the job:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "Output from user script \"$script\" (Exit code = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "Sorry!\n" "\n" msgstr "" "##\n" "## SABnzbd 默认电子邮件模板\n" "## 这是一款 Cheetah 模板\n" "## 文档: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## 新行与空格均有重要意义!\n" "##\n" "## 这些是电子邮件头\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd 已任务 $name\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## 到主体部分时,必须要有空行!\n" "\n" "Hi,\n" "\n" "SABnzbd 已完成 \"$name\" 的下载 \n" "\n" "SABnzbd 下载 \"$name\" 失败 \n" "\n" "完成于 $end_time\n" "已下载 $size\n" "\n" "任务结果:\n" "\n" "Stage $stage \n" "\n" " $result \n" "\n" "\n" "\n" "用户脚本 \"$script\" 输出内容 (退出代码 = $script_ret):\n" "$script_output\n" "\n" "\n" "Enjoy!\n" "\n" "非常抱歉!\n" "\n" #: email/rss.tmpl:1 msgid "" "##\n" "## RSS Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd has added $amount jobs to the queue\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has added $amount job(s) to the queue.\n" "They are from RSS feed \"$feed\".\n" "\n" " $job \n" "\n" "\n" "Bye\n" msgstr "" "##\n" "## SABnzbd RSS 电子邮件模板\n" "## 这是一款 Cheetah 模板\n" "## 文档: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## 新行及空格均有重要意义!\n" "##\n" "## 这些是电子邮件头\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd 已将 $amount 项任务加入队列\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## 到主体部分时,必须要有空行!\n" "\n" "Hi,\n" "\n" "SABnzbd 已将 $amount 项任务加入队列。\n" "它们出自 RSS feed \"$feed\"。\n" "\n" " $job \n" "\n" "\n" "Bye\n" #: email/badfetch.tmpl:1 msgid "" "##\n" "## Bad URL Fetch Email template for SABnzbd\n" "## This a Cheetah template\n" "## Documentation: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## Newlines and whitespace are significant!\n" "##\n" "## These are the email headers\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd failed to fetch an NZB\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## After this comes the body, the empty line is required!\n" "\n" "Hi,\n" "\n" "SABnzbd has failed to retrieve the NZB from $url.\n" "The error message was: $msg\n" "\n" "Bye\n" msgstr "" "##\n" "## SABnzbd 装取 URL 错误电子邮件模板\n" "## 这是一款 Cheetah 模板\n" "## 文档: http://sabnzbd.wikidot.com/email-templates\n" "##\n" "## 新行与空格均有重要意义!\n" "##\n" "## 这些是电子邮件头\n" "To: $to\n" "From: $from\n" "Date: $date\n" "Subject: SABnzbd 装取 NZB 失败\n" "X-priority: 5\n" "X-MS-priority: 5\n" "## 到主体部分时必须要有空行!\n" "\n" "Hi,\n" "\n" "SABnzbd 从 $url 检索 NZB 失败。\n" "错误信息为: $msg\n" "\n" "Bye\n" SABnzbd-2.3.2/po/main/da.po0000644000000000000000000044763213217005051013427 0ustar 00000000000000# Danish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2017-10-27 21:53+0000\n" "Last-Translator: Søren \n" "Language-Team: Danish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:30+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Kunne ikke starte web-interface" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "Kan ikke finde webskabeloner: %s, forsøger med standardskabelon" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" "SABYenc deaktiveret: Der blev ikke fundet nogen korrekt version (Fandt v%s, " "forventede v%s)" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" "SABYenc modul... IKKE fundet! Forventede v%s - https://sabnzbd.org/sabyenc" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "_yenc modul... IKKE fundet!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "par2 binær... IKKE fundet!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "Verificering og reperation er ikke muligt." #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "MultiPar binær... IKKE fundet!" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "Din Unrar version er %s, vi anbefaler version %s eller højere.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "Downloads vil ikke blive udpakket." #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "unrar binær... IKKE fundet!" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "unzip binær... IKKE fundet!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "7za binary... IKKE fundet!" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Vær opmærksom på at 0.0.0.0 værtsnavn har brug for en IPv6-adresse for " "ekstern adgang" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "HTTP og HTTPS porte kan ikke være de samme" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" "SABnzbd blev startet med kodning %s, dette bør være UTF-8. Forvent " "problemer med Unicoded fil- og mappenavne i downloads." #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "HTTPS fejlede på grund af manglende CERT og KEY filer" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Kunne ikke starte web-grænseflade: " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "Kan ikke nå SABHelper tjeneste" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s startet" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Advarsel" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Fejl" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "SABnzbd lukning udført." #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Værtsnavnet er ikke indstillet." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "Der er ingen forbindelser angivet. Angiv mindst én forbindelse." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Kodeord maskeret med ******, forsøg igen" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Ugyldige serverdetaljer" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "Timeout: Forsøg at aktivere SSL eller tilslut via en anden port." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Timeout" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" "Ukendt SSL protokol: Prøv at deaktivere SSL eller forbinder på en anden port." #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Ugyldig server adresse." #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Server afslut under login-sekvens." #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Serveren kræver brugernavn og password." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Tilslutning lykkedes!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Godkendelse mislykkedes, kontrollere brugernavn / adgangskode." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "Alt for mange forbindelser, pause en download eller forsøg igen senere" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Det lykkedes ikke at tilslutte (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Signal %s modtaget, gemmer og lukker..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Fatal fejl ved lagring af state" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Forsøger at hente NZB fra %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Gemmes %s mislykkedes" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Kan ikke oprette temp fil for %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Forsøger at sætte status på ikke eksisterende server %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Fejl i tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Downloadning af %s mislykkedes" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Indlæsning af %s mislykkedes med fejl %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Afprøv notifikation" #: sabnzbd/api.py msgid " Resolving address" msgstr "  Server løsning" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Ingen" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Standard" #: sabnzbd/api.py msgid "unknown" msgstr "Ukendt" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Det lykkedes ikke at kompilere regex for søgestreng: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "For lidt diskplads tvinger system i PAUSE" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Disken er fuld! Pauser..." #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Diskfejl ved oprettelse af fil %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Fatal fejl i Assembler" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" "Advarsel: Pauset job '%s' på grund af krypterede RAR fil (hvis oplyst, alle " "adgangskoder blev forsøgt)" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" "Advarsel: Afbrudt job '%s' på grund af krypterede RAR fil (hvis oplyst, alle " "adgangskoder blev forsøgt)" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Afbrudt, kryptering registreret" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "Advarsel: I \"%s\" uønsket extension i RAR fil. Uønsket fil er \"%s\" " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "Uønsket extension i rar fil %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Afbrudt, uønsket extension fundet" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "ADVARSEL: Pause job \"%s\" på grund af rating (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "ADVARSEL: Afbrudt job \"%s\" på grund af rating (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Afbrudt, rating filter matchede (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s mangler" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "video" #: sabnzbd/assembler.py msgid "audio" msgstr "lyd" #: sabnzbd/assembler.py msgid "spam" msgstr "spam" #: sabnzbd/assembler.py msgid "passworded" msgstr "passworded" #: sabnzbd/assembler.py msgid "downvoted" msgstr "downvoted" #: sabnzbd/assembler.py msgid "keywords" msgstr "nøgleord" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Kvote brugt, pause downloading" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s er ikke en godkendt e-mail adresse" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Kræver serveradresse" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Kan ikke oprette %s mappe %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Kan ikke skrive til INI fil %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Kan ikke oprette backup fil for %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Forkert kodet password%s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s er ikke et korrekt ciffer værdi" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "UNC søgning \"%s\" er ikke tilladt her" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Fejl: Sti længde bør være under %s." #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Fejl: Køen er ikke tom, kan ikke skifte mappe." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "" "Kan ikke skrive til historik database, kontroller adgangsrettigheder!" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "Beskadigede historik database, skabte tom udskiftning" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "SQL Kommando mislykkedes, se logg" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Det lykkedes ikke at lukke databasen, se logg" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Forkert loggning i historiken av %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Afkodning af %s mislykkedes" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "Dekoder fejl: Ikke mere hukommelse" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Forkert udformet yEnc artikel i %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Ukendt fejl under afkodning af %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "UUENCODE detekteret, kun yEnc kodning understøttes [%s]" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => mangler fra alle servere, afviser" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Færdig" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "Udpakket %s filer/mapper i %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "Kan ikke læse %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Det lykkedes ikke at tilføje %s, slette" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Fejl ved fjernelse af %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Kan ikke læse overvåget mappe %s" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Genoptager" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Sat på pause" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Du skal angive den maksimale båndbredde, før du kan angive en båndbredde " "begrænsning" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Server %s vil blive ignoreret for i %s minutter" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Det lykkedes ikke at initialisere %s@%s med begrundelse %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "Alt for mange forbindelser til serveren %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Sandsynligt delt konto" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Det lykkedes ikke at logge på serveren %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Kan ikke tilslutte til server %s [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "Forbindelse %s@%s mislykkedes, besked %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Server %s kræver brugernavn/password" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Suspect fejl i downloader" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Påbegynder lukning af SABnzbd.." #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Det lykkedes ikke at tilslutte mailserver" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "Det lykkedes ikke at initialisere TLS tilslutning" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "Serveren svarede ikke korrekt til helo hilsen" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Godkendelse til mailserver mislykkedes" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Ingen egnet godkendelsesmetode blev fundet" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "Ukendt godkendelsesfejl i mailserver" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Det lykkedes ikke at sende e-mail" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Det lykkedes ikke at lukke e-mail tilslutning" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "E-mail afsendelse mislykkedes" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Kan ikke sende, mangler nødvendige data" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Kan ikke finde e-mail skabeloner i %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Ingen modtagere givet, ingen e-mail sendt" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Ugyldig kodning af e-mail skabelon %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Ingen e-mail skabeloner fundet" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd rapportere Disk Fuld\n" "\n" "Hej,\n" "\n" "SABnzbd er stoppet med at downloade, fordi disken er næsten fuld.\n" "Vær venlig at give plads og genoptage SABnzbd manuelt.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "Advarsel: Localhost er tvetydig, bruge numerisk IP-adresse." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Serveradressen \"%s:%s\" er ikke gyldigt." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "Bruger logget på webgrænsefladen" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "Bruger logget ind" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Mangler sessionsnøgle" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Fejl: Kræver sessionsnøgle" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Fejl: Forkert sessionsnøgle" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "API-nøgle mangler, indtast api-nøglen fra Konfiguration-> Generelt i dit " "tredjepartsprogram:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "Forkert API-nøgle, anvend api-nøglen fra Konfiguration-> Generelt i dit " "tredjepartsprogram:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Brugeroplysninger mangler, indtast brugernavn / password fra Konfiguration-> " "Generelt i dit tredjepartsprogram:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Prøv vores nye hud Glitter! Frisk nyt design, der er optimeret til " "stationære og mobile enheder. Gå til Config - > Generelt for at ændre din " "hud." #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "Mislykkede login forsøg fra %s" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
SABnzbd genstart færdig.
Vent i ca 5 sekunder og klik " "derefter på knappen nedenunder..

Opdater
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Feed" #: sabnzbd/interface.py msgid "Daily" msgstr "Dagligt" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "Mandag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Tirsdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Onsdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Torsdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Fredag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Lørdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Søndag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "slået fra" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Udefineret server" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Fejl parameter" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Tilbage" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "FEJL:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Fejl værdi før %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "d" #: sabnzbd/misc.py msgid "h" msgstr "h" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Kan ikke oprette mappe %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "%s mappe: %s adgang mislykkedes" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Oprettelse af (%s) mislykkedes" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Det lykkedes ikke at flytte %s til %s" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Fejl ved oprettelse af SSL-nøgle og certifikat." #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Det lykkedes ikke at ændre rettigheder på %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Køre script" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Efterbehandling blev afbrudt (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "script" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Udpakning af nesting for dybt [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Sammenlægger" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Ufuldstændig sekvens af filsammenlægning" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Filsammenlægning af %s mislykkedes" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Fejl \"%s\" under filsammenlægning" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Fejl \"%s\" når du køre file_join på %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] Sammen lagte %s filer" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Udpakning mislykkedes, %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Fejl \"%s\" under udpakning af RAR fil(er)" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Fejl \"%s\" når du køre rar_unpack på %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Fjernelse af %s mislykkedes!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Forsøger unrar med adgangskode \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Udpakning mislykkedes, arkivet kræver password" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Udpakker" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Udpak" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Udpakning mislykkedes, kunne ikke finde %s" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "FEJL: lykkedes ikke at finde \"%s\"" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Udpakning mislykkedes, CRC-fejl" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "FEJL: CRC mislykkedes i \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "Udpakning mislykkedes, skrivefejl eller disken fuld?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "FEJL: skrivefejll (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Udpakningen mislykkedes, stien er for lang" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "FEJL: stien for lang (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Udpakning mislykkedes, se logg" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "FEJL: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Ubrugelig RAR fil" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "Ødelagt RAR fil" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s filer i %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Fejl \"%s\" når du køre unzip() på %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Forsøger 7zip med password \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "7ZIP sæt \"%s\" er ufuldstændig, kan ikke udpakke" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Kan ikke udpakke %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Hurtig kontrollerende" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Reparér" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Hurtig kontrol OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Starter reparation" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "Par verificering mislykkedes på %s, mens QuickCheck lykkedes" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Reparation mislykkedes, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Fejl %s når du kører par2_repair på %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Fejl \"%s\" mens par2_repair kørte på %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] PAR2 modtog forkerte indstillinger, tjek din konfiguration->Skifter " "indstillinger" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Bekræftelse i %s, alle filer er ok" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Bekræftelse i %s, kræver reparation" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "Henter %s block..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Henter" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "Reparation mislykkedes, ikke nok reparation blokke (%s mangler)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Reparerer" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Repareret i %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Disk fuld" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Bekræfter" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Kontrollerer" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "Python script '%s' har ikke udfør (+x) tilladelsessæt" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Denne server tillader ikke SSL på denne port" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "Server %s bruger et upålidelig certifikat [%s]" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Start / Lukning" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "Tilføjet NZB" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Efterbehandling i gang" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Job afsluttet" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Jobbet misllykedes" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Kø færdig" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Andre beskeder" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Ikke tilgængelig" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Kunne ikke sende Prowl besked" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Dårlig respons fra pushover (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Det lykkedes ikke at sende pushover besked" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Dårlig respons fra pushbullet (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Det lykkedes ikke at sende pushbullet besked" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "Script returnerede exit kode %s og output \"%s\"" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "Notification scriptet \"%s\" findes ikke" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "Det lykkedes ikke at sende Windows notification" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "Gamle kø opdaget, bruge Status-> reparation for at konvertere kø" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Ødelagt kø-fil fundet, kan ikke fortsætte" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Downloadnings fejl %s, ødelagt fil fundet" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "Det lykkedes ikke at genstarte NZB efter præ-kontrol (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB tilføjet i køen" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Ukendt kodning" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Fil %s er tom, springer over" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Det lykkedes ikke at importere %s filer fra %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Ufuldstændig NZB fil %s" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Ødelagt NZB fil %s, springer over (årsag=%s, linje=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Tom NZB fil %s" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "Før-kø script job markeret som mislykkedet" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Ignorerer identiske NZB \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "Fejler dublet NZB \"%s\"" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "Dublet NZB" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Pause duplikeret NZB \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Afbrudt, kan ikke afsluttes" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "DUPLIKERE" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "KRYPTEREDE" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "FOR STOR" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "Ufuldstændig" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "Uønsket" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "FILTERED" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "VENT %s sekunder" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "PROPAGATING %s min" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Hentede i %s med et gennemsnit på %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Alder" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s artikler misdannede" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s artikler manglede" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s artikler havde ikke-matchende dubletter" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s artikler blev fjernet" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Det lykkedes ikke at importere %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Advarsler" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Inaktiv" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Opsætning" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Kø" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Rens køen" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Historik" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Tøm historik" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Hastighedsbegrænsning" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Pause" #: sabnzbd/osxmenu.py msgid "min." msgstr "min." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Genoptag" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Scan overvåget mappe" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Læs alle RSS feeds" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Færdig mappe" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Ufuldstændig mappe" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Fejlfinding" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Genstart" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Genstart uden login" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Afslut" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Kø (de første 10 poster)" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Tom" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Historik (de 10 seneste poster)" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Ny version tilgænglig" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Gå til guiden" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Standser" #: sabnzbd/panic.py msgid "Problem with" msgstr "Problem med" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd har brug for en ledig TCP / IP-port til sine interne " "webserver.
\n" " Port %s på %s blev forsøgt, men den er ikke til rådighed .
\n" " Nogle andre programmer bruger porten eller SABnzbd kører allerede.
\n" "
\n" " Genstart venligst SABnzbd med et andet portnummer." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "Hvis du får denne fejlmeddelelse igen, prøv et andet portnummer.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd har brug for en gyldig vært adresse til intern webserver .
\n" " Du har angivet en ugyldig adresse.
\n" " Sikkert valg er localhost og 0.0.0.0
\n" "
\n" " Venligst genstart SABnzbd med en gyldig host adresse ." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd har fundet gemt data fra en anden SABnzbd version
\n" " men kan ikke genbruge dataene fra det andet program.

\n" " Du ønsker måske at afslutte din kø først med det andet program.

\n" " Efter dette, start programmet med \"- rene\" valgmulighede.
\n" " Dette vil slette den nu værende kø og historik!
\n" " SABnzbd læser filen \"%s\"." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd kan ikke finde sin webgrænseflade filer i %s.
\n" " Venligst installer programmet igen.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd fandt en alvorlig fejl:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd opdagede, at filen sqlite3.dll mangler .

\n" " Nogle dårligt designet virus-scannere fjernede denne fil .
\n" " Tjek venligst din virus-scanner, du kan prøve at geninstallere SABnzbd " "og klage til din virus-scanner leverandør .
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Tryk Startkey + R og skriv linjen (eksempel):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Åben et terminalvindue og tast linjen (eksempel):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Programmet startede ikke!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Alvorlig fejl" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "Kan ikke starte browseren, sandsynligvis ikke fundet" #: sabnzbd/panic.py msgid "Access denied" msgstr "Adgang nægtet" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Fejl %s: Du skal angive et gyldigt brugernavn og adgangskode." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "Overførslen kan mislykkes, kun %s af det krævede %s tilgængelig" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Download mislykkedes - ikke på din server (e)" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Ingen efterbehandling på grund af mislykket godkendelse" #: sabnzbd/postproc.py msgid "Moving" msgstr "Flytter" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "Sendt %s til kø" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Det lykkedes ikke at omdøbe \"%s\" til \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Kunne ikke flytte filer" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Kør bruger script %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "Kørte %s" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Script exit kode er %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Mere" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Efterbehandling mislykkedes for %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "se logfil" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Download mislykkedes" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Fjernelse af %s mislykkedes." #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Det lykkedes ikke at fjerne arbejdsmappen (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Overførsel fuldført" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Kan ikke oprette endelig mappe %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Efterbehandling" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Ingen par2 sæt" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Forsøger SFV verifikation" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Some files failed to verify against \"%s\"" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Kontrolleret korrekt ved hjælp af SFV filer" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "Forsøger RAR-baseret kontrol" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "[%s] RAR-baserede kontrollen mislykkedes: %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "Behov adgangskode" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "RAR filer kontrolleres med succes" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "RAR filer kunne ikke bekræfte" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Fjernelse af%s mislykkedes" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Det lykkedes ikke systemet at gå i dvale" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Det lykkedes ikke systemet at gå i standby" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Fejl ved lukning af system" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "Indexer id (%s) ikke fundet for ratings fil" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Serveradresse" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "API-nøgle" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" "Denne nøgle indeholder identitet indekseringen. Tjek din profil på " "indekseringens hjemmeside." #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Forkert RSS-feed beskrivelse \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Mislykkedes at hente RSS fra %s: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Har ikke gyldig godkendelse til feed %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "Server fejl (server kode %s); kunne ikke få %s på %s" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "Server %s bruger et upålideligt HTTPS-certifikat" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "RSS Feed %s er tom" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Inkompatibel feed" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Tom RSS post blev fundet (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Vis grænseflade" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Åben færdig mappe" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Luk ned" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Tilbageværende" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Tilføj NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Forkert tidsplan %s ved %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Ukendt handling: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Tidsplan for ikke-eksisterende server %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Downloader" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Sammenlægger filer" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Kilde" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Server" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Mislykkedes" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Mislykkedes" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "Venter" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Reparerer..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Udpakning..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Flytter..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Kør script..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Henter ekstra block..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Hurtig kontrol..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Bekræftelse..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Downloader" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "Propagation delay" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Forekomst" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Udfør" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Argumenter" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Opgave" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "deaktivere server" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "aktivere server" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Hastighedsbegrænsning" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Pause alt" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Pause efterbehandling" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Genoptag efterbehandling" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Læs RSS feeds" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Fjern mislykkede jobs" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Fjern fuldførte job" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Pause lav prioritets jobs" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Pause normal prioritets jobs" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Pause høj prioritets jobs" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Genoptag lav prioritets jobs" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Genoptag normal prioritets jobs" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Genoptag høj prioritets jobs" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Aktivere kvota styring" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Deaktivere kvota styring" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Slået fra" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Meget lav" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Moderat" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normal" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Høj" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Nødsituation" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Lav" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "MB" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "GB" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "time" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "timer" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "minut" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "minutter" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "sekund" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "sekunder" #: sabnzbd/skintext.py msgid "day" msgstr "dag" #: sabnzbd/skintext.py msgid "days" msgstr "dage" #: sabnzbd/skintext.py msgid "week" msgstr "uge" #: sabnzbd/skintext.py msgid "Month" msgstr "Måned" #: sabnzbd/skintext.py msgid "Year" msgstr "År" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Månedsdag" #: sabnzbd/skintext.py msgid "This week" msgstr "Denne uge" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Denne måned" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "I dag" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Totalt" #: sabnzbd/skintext.py msgid "on" msgstr "på" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parameter" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Python-version" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Startside" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "eller" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Vært" #: sabnzbd/skintext.py msgid "Comment" msgstr "Kommentar" #: sabnzbd/skintext.py msgid "Send" msgstr "Send" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Annullér" #: sabnzbd/skintext.py msgid "Other" msgstr "Andet" #: sabnzbd/skintext.py msgid "Report" msgstr "Rapportér" #: sabnzbd/skintext.py msgid "Video" msgstr "Video" #: sabnzbd/skintext.py msgid "Audio" msgstr "Audio" #: sabnzbd/skintext.py msgid "Not used" msgstr "Bruges ikke" #: sabnzbd/skintext.py msgid "or less" msgstr "eller mindre" #: sabnzbd/skintext.py msgid "Log in" msgstr "Log in" #: sabnzbd/skintext.py msgid "Log out" msgstr "Log ud" #: sabnzbd/skintext.py msgid "Remember me" msgstr "Husk mig" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "Det automatiske usenet download værktøj" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Gem" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Er du sikker?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Slet alle hentede filer?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Hjem" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Konfiguration" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Status" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Hjælp" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Forum" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "Problemer" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "Støt projektet, donér!" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Generelt" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Mapper" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Parameter" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Planlægning" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Meddelelser" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "E-mail" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Kategorier" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Sortering" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Speciel" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Søg" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Download mappe" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "PAUSET" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "Cached %s artikler (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Sysload" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Ny version %s tilgængelig" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Er du sikker på du vil lukke SABnzbd?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Tilføj" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Tilføj fil" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Kategori" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Forløb" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Prioritet" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Reparere" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Udpakke" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Slette" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "P" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "T" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Tvinge" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Stop" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "Når køen er færdig" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Luk computer" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "Sæt computer i standby" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Sæt computer i dvale" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Afslut SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Hastighedsbegrænsning" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Pause i" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Rækkefølge" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Navn" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "Tid tilbage" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "Alder" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Fjern" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Forsøg igen" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Handlinger" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Scripts" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Fjern alt fra køen?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Rens NZB'er" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Rens NZB'er & slet filer" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Prøv igen alle mislykkede job" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Fjern NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Fjern NZB & slet filer" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "fra" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Mangler artikler" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Kvota tilbage" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "manuelt" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Nulstil kvota nu" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Slet alle afsluttede emner fra historie?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Skjul detaljer" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Vis detaljer" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Vis mislykket" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Vis Alt" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Størrelse" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Rens mislykket NZB'er" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Rens mislykket NZB'er & slet filer" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Rens komplette NZB'er" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "Rens NZBs på den aktuelle side" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "Valgfri Supplerende NZB" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Sti" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Prøv igen alle mislykkede" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Prøv igen alle" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus/spam" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "Udenfor retention" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Et andet problem" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Gennemtving afbrydelse" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Dette vil sende en test E-mail til din konto." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Vis log" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Test E-mail" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Logning" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Fejl/Advarsel" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ Info" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "Fejlfinding" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Forbindelser" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Seneste advarsler" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "Slet" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Ophæv blokering" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Artikel identifikator" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Fil sæt" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Når" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Type" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Aktiveret" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Oversigt" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Tilslutning mislykkedes!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Lokal IPv4 adressse" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Offentlig IPv4 adresse" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "IPv6 adresse" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Nameserver / DNS Lookup" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "CPU Model" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "System Performance (Pystone)" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Download mappe hastighed" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Komplet mappe hastighed" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Skrive hastighed" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "Kunne ikke skrive. Kontrollér, at mappen er skrivbar." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Klik på gentagelse testknappen nedenfor for at afgøre" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Gentagelse test" #: sabnzbd/skintext.py msgid "Config File" msgstr "Konfigurations fil" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Brugt chace" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Knappen vil genstarte SABnzbd..
\r\n" "Andvend den hvis du oplever stabilitets problem.
\r\n" "Downlodning vil blive sat på pause før genstart og genoptages automatisk " "igen efter genstart." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "
Hvis godkendelse er aktiveret, skal du logge ind igen." #: sabnzbd/skintext.py msgid "Advanced" msgstr "Avanceret" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Der er forældreløse jobs i download mappen.
Du kan vælge at slette " "dem (herunder filer) eller sende dem tilbage til køen." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "\"Reparation\" knappen vil genstarte SABnzbd og lave en komplet
" "rekonstruktion af køens indhold, bevare allerede downloadede filer.
" "Dette vil ændre køens orden." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Ændringerne er ikke gemt og vil blive mistet." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" "Når din IP-adresse ændres eller SABnzbd genstarter, udløber sessionen." #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Aktivér Unzip" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "Aktivere 7zip" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" "Sikker (SSL) forbindelser fra SABnzbd til nyhedsserverne og HTTPS " "hjemmesider vil blive krypteret, dog validering af en servers identitet ved " "hjælp af sine certifikater er ikke mulig. Python 2.7.9 eller derover, " "OpenSSL 1.0.2 eller derover og op-to-date kræves lokale CA certifikater." #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" "Fremskynde reparationer ved at installere multicopy Par2, det findes til " "mange platforme." #: sabnzbd/skintext.py msgid "Version" msgstr "Udgave" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Oppetid" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Sikkerhedskopi" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Læs mere om dette på Wiki Help!" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Genstarter SABnzbd..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Ændringer kræver genstart af SABnzbd!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "SABnzbd Webserver" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "SABnzbd Adresse" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Adresse som SABnzbd ska lytte på." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "SABnzbd Port" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Port som SABnzbd ska lytte på." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Webgrænseflade" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Vælg et Web-grænseflade udseende." #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "SABnzbd brugernavn" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Valgfrit brugernavn." #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "SABnzbd password" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Valgfrit password." #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "Sikkerhed" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "HTTPS Aktivering" #: sabnzbd/skintext.py msgid "not installed" msgstr "ikke installeret" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Aktiver adgang til interface fra en HTTPS-adresse." #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "HTTPS Port" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Hvis tom, vil standard-porten kun lytte til HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "HTTPS Certifikat" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Filnavn eller sti til HTTPS Certifikat." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" "Generer ny selvsigneret certifikat og nøgle. Kræver SABnzbd genstart!" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "HTTPS Nøgle" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Filnavn eller sti til HTTPS Nøgle." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "HTTPS kæde certifikater" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Filnavn eller sti til HTTPS kæde." #: sabnzbd/skintext.py msgid "Tuning" msgstr "Justering" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "RSS Opdaterings interval" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Kontrol af interval (i minutter, i hvert fald 15). Ikke aktiv, når du bruger " "skemaer!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Maksimal linje hastighed" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Procentvis af linje hastighed" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "Hvilken procentdel af linje hastighed bør SABnzbd bruge, fx 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Cache størrelse af artikler" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Cache artikler i hukommelsen for at reducere diskadgang.
I bytes, " "efterfulgt af K,M,G. For eksempel: \"64M\" eller \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Ryd listen" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Listen over filtypenavne, der skal slettes efter download. < br / > For " "eksempel: nfo eller nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Gem ændringer" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "Gendan standardværdier" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Nulstil" #: sabnzbd/skintext.py msgid "Language" msgstr "Sprog" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Vælg et web-grænseflade sprog." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" "Hjælp os med at oversætte SABnzbd på dit sprog!
Tilføj uoversatte " "tekster eller forbedrede eksisterende oversættelser her:" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "Denne nøgle vil give 3. parts programmer fuld adgang til SABnzbd." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "NZB nøgle" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "Denne nøgle vil give 3. parts programmer til at tilføje NZBs til SABnzbd." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Generere Ny Nøgle" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "API nøgle QR kode" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Liste over lokale netværk intervaller" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Alle lokale netværksadresser starter med disse præfikser (ofte " "\"192.168.1.\")" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Eksterne internetadgang" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" "Du kan angive adgangsrettigheder for systemer uden for dit lokale netværk. " "Kræver liste over lokale netværks intervaller, skal defineres." #: sabnzbd/skintext.py msgid "No access" msgstr "Ingen adgang" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Tilføj NZB filer " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (ingen konfiguration)" #: sabnzbd/skintext.py msgid "Full API" msgstr "Fuld API" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Fuld webinterface" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "Kun ekstern adgang kræver login" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "OBS: Mapper vil blive oprettet automatisk, når du gemmer. Du kan " "bruge absolutte stier til at gemme uden for standardmapperne." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Brugermapper" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Gennemse" #: sabnzbd/skintext.py msgid "In" msgstr "Ligger i" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Midlertidig download mappe" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Sted at gemme uforarbejdede downloads.
Kan kun ændres, når køen er " "tom." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Minimum fri plads til midlertidige download mappe" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Auto-pause, når ledig plads kommer under denne værdi.
I bytes, " "evt. efterfulgt af K, M, G, T. For eksempel: '800M 'eller '8 G'" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Færdig download mappe" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Sted at opbevare færdige, fuldt forarbejdede downloads.
Kan " "tilsidesættes af bruger-definerede kategorier." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Tilladelser til fuldførte overførsler" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Angive tilladelses mønster for afsluttede filer.
Anvend ciffer. For " "eksempel: \"755\" eller \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Overvåget Mappe" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Mappe til at gennemsøge for. Nzb filer.
Skanner også for .zip .rar " "og .tar.gz arkiver efter .nzb filer." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Skannings interval for overvåget mappe" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Sekunder mellem skanninger for .nzb filer." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "Scripts mappe" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "Mappe, der indeholder bruger-scripts." #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "E-mail-mappe skabeloner" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Mappe, der indeholder brugerdefinerede e-mail-skabeloner." #: sabnzbd/skintext.py msgid "Password file" msgstr "Password-fil" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Fil, der indeholder alle passwords. Vil blive brugt på password beskyttede " "RAR filer." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Systemmapper" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Administrativ mappe" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Placering for kø administrativ og historik database.
Kan kun ændres, " "når køen er tom." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "Data vil ikke blive flyttet. Kræver SABnzbd genstartet!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Log mappe" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Placering af logfiler for SABnzbd.
Kræver genstart af SABnzbd!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr ".nzb Backup mappe" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Sted hvor .nzb filer gemmes." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Standard Base Folder" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Download alle par2 filer" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" "Dette forhindrer flere reparationer kører ved at downloade alle par2 filer " "når det er nødvendigt." #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Aktivere rekursive udpakning" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Udpakke arkiver (rar, zip, 7z) i arkiver." #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Ignorere hvilken som helst mappe indeni arkiv" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Alle filer vil ligges ind i en enkelt mappe." #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Kun artiklerne fra starten af køen" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Aktiver til mindre brug af hukommelse. Deaktiver for at forhindre langsom " "job fra at blokerer køen" #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Efterbehandling kun verificerede jobs" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "Kun udføre efterbehandling af jobs som har bestået PAR2 kontrollen." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Handling når krypteret RAR er downloadet" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "I tilfælde af \"Pause\", skal du angive en adgangskode og genoptage jobbet." #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Find identiske downloads" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" "Fundet identiske NZB filer (baseret på elementer i din historik eller filer " "i. nzb Backup mappe)" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Opdage identiske episoder i serier" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" "Fundet identiske episoder i serie (baseret på \"navn /sæson /episode\" af " "elementer i din historik)" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Kassér" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "Mislykkes job (flyt til historik)" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Afbryd" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Aktion når uønsket extension er fundet" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "Aktion når uønsket extension er fundet i RAR fil" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Uønsket extension" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Vis alle uønskede extensions. For eksempel: exe or exe, com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Aktiver SFV-baseret kontrol" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Udfør en ekstra kontrol baseret på SFV-filer." #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Bruger-script kan markere et job som mislykket" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Når bruger scriptet returnerer et non-zero exit code, vil jobbet blive " "markeret som mislykkedes" #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "Ved fejl, prøv alternativ NZB" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "Nogle servere levere en alternativ NZB når et download mislykkes." #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Aktiver mappe omdøbning" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Brug midlertidig navne under efterbehandling. Deaktiver når dit system ikke " "kan håndtere det ordentligt." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Før kø bruger script" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Brugt før, en NZB kommer ind i køen." #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Ekstra PAR2 parameter" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "God parameter" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "IONice parametre" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Afbryd når køen er tom" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "Afbryd fra usenet-serverne når køen er tom eller sat på pause." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Sortere efter alder" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Sortere automatisk efter (gennemsnits) alder." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" "Indlæg vil blive sat på pause indtil de har mindst denne alder. Indstilling " "af job prioritet til Tvang vil springe forsinkelsen over." #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Kontroller for ny version" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Kontroller for ny version af SABnzbd hver uge." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "Test også udgivelser" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Erstat mellemrum i mappenavn" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Erstat mellemrum med understreg i mappenavn." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Erstat punktummer i mappenavn" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Erstat punktum med mellemrum i mappenavn" #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Gør Windows kompatibel" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "For servere: Kontroller navne er kompatibel med Windows." #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Start web browser ved opstart" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Starter standard web browser når SABnzbd starter." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Pause downloading under efterbehandling" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Pauser downloadet i begyndelsen af efterbehandling og igen når den er færdig." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Ignorer Sample-filer" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Filtrerer prøve filer (f.eks. video eksempler)." #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Fjern efter download" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "verifikation HTTPS certifikat" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" "Kontroller certifikater, når du opretter forbindelse til indeksører og RSS-" "kilder ved hjælp HTTPS." #: sabnzbd/skintext.py msgid "Server" msgstr "Server" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Efterbehandling" #: sabnzbd/skintext.py msgid "Naming" msgstr "Navngivning" #: sabnzbd/skintext.py msgid "Quota" msgstr "Kvota" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indeksering" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Hvor meget der kan downloades i denne måned (K / M / G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Nulstil dag" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "På hvilken dag i måneden eller ugen (1 = mandag) nulstiller din " "internetudbyder kvota? (Valgfrit med tt: mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Automatisk genoptag" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "Skal download genoptages efter kvotaen er nulstillet?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Kvota periode" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "Bliver kvota nulstillet hver dag, uge ​​eller måned?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Tjek før download" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Prøv at forudsige en vellykket afslutning, før selve download (langsom!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "SSL-chifre" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "Øge ydeevnen ved at tvinge en lavere SSL-kryptering styrke." #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Maksimalt antal forsøg" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Maksimalt antal forsøg per server" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Afbryd job, der ikke kan færdiggøres" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Når under download det bliver klart, at for meget data mangler, afbryd jobbet" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "Aktiver indekseringen Integration" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Aktivere filtrering" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Håndter downloads efter filtrering regler." #: sabnzbd/skintext.py msgid "Abort If" msgstr "Afbryd hvis" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Ellers pause hvis" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Video rating" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Lyd rating" #: sabnzbd/skintext.py msgid "Spam" msgstr "Spam" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Bekræftet" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Flere thumbs ned end op" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Titel nøgleord" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Kommasepareret liste" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Server belastningsjustering" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Forhindre belastningsjustering" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Tillad belastningsjustering" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Giver mulighed for belastningsjustering med optimering for IPv6" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "Nyttigt, hvis en newsserver har mere end én IPv4/IPv6-adresse" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Tilføj server" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Serverbeskrivelse" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Port" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Brugernavn" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Kodeord" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Tidsudløb" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Tilgængelighed i dage" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "Sikker forbindelse til server" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "Certifikatkontrol" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Deaktiveret" #: sabnzbd/skintext.py msgid "Minimal" msgstr "Minimal" #: sabnzbd/skintext.py msgid "Strict" msgstr "Streng" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 er højeste prioritet, 100 er den laveste prioritet" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Valgfri" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" "For upålidelige servere, vil blive ignoreret længere i tilfælde af fejl" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Aktivere" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Fjern server" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Testserver" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Nulstil tæller" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Tester serverdetaljer..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Båndbredde" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Send gruppe" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Send gruppe kommandoen, før du anmoder om artikler." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Brug kun denne server for disse kategorier." #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" "Ingen af ​​de aktiverede servere har kategorien 'Standard' valgt. Job i køen " "som ikke er tildelt en af ​​serverens kategorier vil ikke blive downloadet." #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Personlige notater" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Opret planlægning" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Aktuel planlægning" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "Afkrydsningsfeltet ud for feed navn skal afkrydses for at feeds vil være " "aktiveret og automatisk kontrolleres for nye emner.
Når et feed er " "tilføjet, vil det kun hente nye informationer og ikke noget, der allerede " "findes i RSS-feed, medmindre du trykker på \"Force Download\"." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "Adskil flere URL-adresser med komma" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Læs Feed" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Gennemtving download" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Filter" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Acceptere" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Afvise" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Kræver" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "Kræver Cat" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Mindst" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Højst" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "Fra SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "Fra Show SxxEyy" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Matchede" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Matchede ikke" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Hentet" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Læs alle Feeds nu" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "E-mail påmindelse når job er fuldført" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Aldrig" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Altid" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Kun ved fejl" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Påmindelse når harddisk er fyldt" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "Send e-mail når harddisken er fyldt og SABnzbd er pauset." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Send RSS meddelelser" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "Send e-mail når en RSS-feed tilføjer job i køen." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "SMTP-server" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Indtast ISP's server for udgående e-mail." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "E-mail modtagere" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "E-mail adresse hvor den skal sendes til." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "E-mail sendere" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Hvem skal vi sige sendte e-mailen?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "VALGFRIT konto brugernavn" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Brugernavn for e-mail som kræver godkendelse." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "VALGFRIT Bruger password" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Password for e-mail som kræver godkendelse." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Aktiver Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Send meddelelser til Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Bruges kun ved Growl fjern server (vært: port)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Serverkodeord" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Valgfri adgangskode til Growl server" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "Aktiver NotifyOSD" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Send meddelelser til NotifyOSD" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Notification Center" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Send notifications to Notification Center" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Aktiver Windows notifikationer" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Windows Notifikationer" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Aktivere Prowl notifikation" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Kræver en Prowl konto" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "API nøgle for Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Personlig API nøgle for Prowl (påkrævet)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Aktivere Pushover anmeldelser" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Kræver en Pushover konto" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Program token" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Program token (krævet)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Bruger nøgle" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Bruger nøgle (krævet)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Enhed(er)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Enhed(er) som meddelelse skal sendes til" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Aktiver Pushbullet notifikationer" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Kæver en Pushbullet konto" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Personlig API nøgle" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Din personlige Pushbullet API nøgle (krævet)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Enhed" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Enhed som meddelse skal sendes til" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "Notification Script" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "Aktivere notification script" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "Udfører et brugerdefineret script" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "Hvilke script skal vi udføre for notification?" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" "Indeksatorer kan levere en kategori inde NZB som SABnzbd vil forsøge at " "matche de kategorier defineret nedenfor. Derudover kan du føje betingelser " "til ' indekseringen kategorier / grupper til at matche flere kategorier. " "Brug kommaer til at adskille vilkår. Jokertegn i vilkårene er understøttet." #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Slutter stien med en stjerne *, vil forhindre oprettelse af ​​job mapper." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Relative mapper er baseret på" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Mappe/Søgesti" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "Indekseringen kategorier / grupper" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Serie sortering" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Aktivere TV sortering" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Hjælp til Sorteringsstræng" #: sabnzbd/skintext.py msgid "Clear" msgstr "Ryd" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "Anvend filtre" #: sabnzbd/skintext.py msgid "Presets" msgstr "Forudindstillinger" #: sabnzbd/skintext.py msgid "Example" msgstr "Eksempel" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "Film sortering" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Aktivere filmsortering" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Behold løse download i ekstra mapper" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Påvirkede Kategorier" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Betyder" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Mønster" #: sabnzbd/skintext.py msgid "Result" msgstr "Resultat" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Sæsonmappe" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Sæsonmappe" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Episodemappe" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Episodemappe" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Titel" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Film Navn" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Film.Navn" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Film_Navn" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Vis navn" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Vis.Navn" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Vis_Navn" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Sæsonnummer" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Episodenummer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Episodenavn" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Episode.Navn" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Episode_Navn" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Filtype" #: sabnzbd/skintext.py msgid "Extension" msgstr "endelse" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Delnummer" #: sabnzbd/skintext.py msgid "Decade" msgstr "Årti" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Originalfilnavn" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Små bogstaver" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEKST" #: sabnzbd/skintext.py msgid "text" msgstr "tekst" #: sabnzbd/skintext.py msgid "file" msgstr "fil" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Sorteringsstreng" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Multi-del etikette" #: sabnzbd/skintext.py msgid "In folders" msgstr "I mappe" #: sabnzbd/skintext.py msgid "No folders" msgstr "Ingen mappe" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Dato sortering" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Aktivere datosortering" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Vis Navn på mappe" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "År-Måned mapper" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Daglige mapper" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "sag-justeret" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Forarbejdede resultat" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Sjældent anvendte indstillinger. Deres betydning og forklaring, klik på " "knappen Hjælp for at gå til siden Wiki.
Ændre ikke disse uden at " "kontrollere wiki'en først, da disse kan give alvorlige side " "følger.
Standardværdierne er mellem parenteserne." #: sabnzbd/skintext.py msgid "Values" msgstr "Værdier" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Ændre NZB detaljer" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Slet" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Øverst" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Op" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Ned" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Bunden" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Alle" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Invertere" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Filnavn" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Emne" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Udvælgelse" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Pause 5 minutter" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Pause 15 minutter" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Pause 30 minutter" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Pause 1 time" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Pause 3 timer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Pause 6 timer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "tilbage" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Ledig diskplads" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Midlertidig mappe" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Multi-operationer" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Hold Skiftetasten nede for at vælge et område" #: sabnzbd/skintext.py msgid "Check all" msgstr "Tjek alle" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Genstart SABnzbd" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Status og grænseflade indstillinger" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Eller trække og slippe filer i vinduet!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Mistet forbindelsen til SABnzbd.." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "I tilfælde af SABnzbd genstart vil denne skærm forsvinde automatisk!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "ADVARSEL:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Hent" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Opdateringsfrekvens" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Brug globale grænseflade indstillinger" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Køen elementbegrænsning" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Historie Elementbegrænsning" #: sabnzbd/skintext.py msgid "Date format" msgstr "Datoformat" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Ekstra kø kolonne" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "Ekstra kolonne historie" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "side" #: sabnzbd/skintext.py msgid "Loading" msgstr "Indlæser..." #: sabnzbd/skintext.py msgid "articles" msgstr "artikler" #: sabnzbd/skintext.py msgid "Rename" msgstr "Omdøbe" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Kø reparation" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Vis aktive forbindelser" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Forældreløse jobs" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Send tilbage til køen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Fjern alle" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Prøv igen alle" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Hent NZB fra URL" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "Upload NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Angiv et valgfrit filnavn" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Formater: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Tilføj" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Åbn informations URL" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Tilføjet. Mange tak!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Intet er valgt!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Fjern alle valgte filer" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Skjul/Vis komplette filer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Vis scriptlog" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Opdatering tilgængelig" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" "LocalStorage (cookies) er deaktiveret i din browser, indstillinger for " "brugergrænsefladen vil gå tabt, når du lukker browseren!" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "Glitter har nogle (nye) egenskaber, du kan lide!" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Tilpasse" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "Kompakt layout" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "Tabbed layout
(separat kø og historie)" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Hastighed" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Bekræft Kø-fjernelse" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Bekræft Historik-fjernelse" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Hvor længe eller indtil hvornår du vil standse? (på engelsk!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Vi kunne desværre ikke fortolke denne. Prøv igen." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Pause i..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Opdatere" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Sortere efter alder Ældst→Nyeste" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Sortere efter alder Nyeste→Ældst" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Sortere efter navn A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Sortere efter navn Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Sortere efter størrelse Mindst→Størst" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Sortere efter størrelse Størst→Mindst" #: sabnzbd/skintext.py msgid "Uploading" msgstr "Uploader" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "Tvinge afbrydelse" #: sabnzbd/skintext.py msgid "Removing job" msgstr "Fjernelse af job" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "Fjernelse af jobs" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Foregående" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Næste" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Vil du virkelig tømme historiken?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Du skal aktivere JavaScript for at få Plush til virke!" #: sabnzbd/skintext.py msgid "Options" msgstr "Muligheder" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Pause i hvor mange minutter?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Topmenu" #: sabnzbd/skintext.py msgid "On Finish" msgstr "Ved afslutning" #: sabnzbd/skintext.py msgid "Sort" msgstr "Sortere" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Sortere efter Alder (Ældst→Nyeste)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Sortere efter Alder (Nyeste→Ældst)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Sortere efter Navn (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Sortere efter Navn (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Sortere efter Størrelse (Mindst→Størst)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Sortere efter Størrelse (Størst→Mindst)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Tøm køen?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Prøv igen alle mislykkede job i historien?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Ryd" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Max hastighed" #: sabnzbd/skintext.py msgid "Range" msgstr "Interval" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Anvend på markerede" #: sabnzbd/skintext.py msgid "Everything" msgstr "Alt" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Opdateringsinterval" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Beholder Bredde" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "" "Dette vil forhindre indhold i at blive opdateret når musens markør kører hen " "over køen" #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Bloker genopfriskninger ved at hænge over" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Upload" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Upload: .nzb .rar .zip .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Fremgang" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Ikke nok diskplads til at fuldføre downloads." #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Ledig tempdiskplads" #: sabnzbd/skintext.py msgid "IDLE" msgstr "Venter" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Hentede filer" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Slet komplette" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Slet alle mislykkedes emner fra historiken?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Slet mislykket" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Prøv igen alle mislykkede job?" #: sabnzbd/skintext.py msgid "Links" msgstr "Links" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Viser %s til %s af %s resultat" #: sabnzbd/skintext.py msgid "No results" msgstr "Ingen resultater" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Viser et resultat" #: sabnzbd/skintext.py msgid "First" msgstr "Først" #: sabnzbd/skintext.py msgid "Last" msgstr "Sidste" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "Sendt E-mail!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Notifikation sendt" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Gemmer.." #: sabnzbd/skintext.py msgid "Saved" msgstr "Gemt" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Vis/Skjul Tilføj NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "Flerskærme1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "Flerskærme2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Er du sikker på at du vil genstarte SABnzbd?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Skjul Redigeringsalternativ" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Vis Redigeringsalternativ" #: sabnzbd/skintext.py msgid "Edit" msgstr "Rediger" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Resterende tid" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "SABnzbd Hurtigstart’s Guide" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "SABnzbd version" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Forrige" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Serverdetaljer" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Angiv detaljerne fra din primære usenet udbyder." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Antallet af forbindelser tilladt af din udbyder" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "F.eks. 8 eller 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Vælg kun hvis din udbyder tillader SSL-forbindelser." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Klik for at teste de indtastede informationer." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Eks." #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "Installationen er nu fuldført!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd vil nu køre i baggrunden." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "Lukning af alle browservinduer / faneblade vil ikke lukke SABnzbd." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Det anbefales, at du højreklikker og bogmærker denne placering, og bruger " "dette bogmærke for at få adgang SABnzbd, når det kører i baggrunden." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Øvrig hjælp kan du finde på vores" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Gå til SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Afslut SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Start guide" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd kommer med ABSOLUT INGEN GARANTI. \n" "Det er gratis software, og du er velkommen til at videredistribuere det " "under visse betingelser. \n" "Den er licenseret under GNU General Public License version 2 eller (efter " "eget valg) enhver senere version\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "For at hente fra usenet kræves der adgang fra en udbyder. Din " "internetudbyder kan give dig adgang, men en præmie udbyder anbefales." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "Har du ingen usenet leverandør? Vi anbefaler at prøve %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Det lykkedes ikke at hente TV info (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Det lykkedes ikke at omdøbe: %s til %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Kunne ikke omdøbe lignende fil: %s til %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Servernavnet løser ikke" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Uautoriseret adgang" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "Fil ikke på server" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "Serveren kunne ikke fuldføre anmodningen" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "URLGRABBER CRASHED" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Fejl, Ubrugelig arkivfil" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "URL hentning mislykkedes; %s" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "Mappen \"%s\" findes ikke" #~ msgid "SQL Commit Failed, see log" #~ msgstr "SQL Commit mislykkedes, se logg" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "CRC Fejl i %s (%s -> %s)" #~ msgid "Error: No secondary interface defined." #~ msgstr "Fejl: Ingen sekundær bruger grænseflade defineret." #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Din unrar version kan ikke anbefales, hent UNRAR fra " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "Ingen unrar program fundet, udpakning RAR filer er ikke mulig
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "Ingen PAR2 program fundet, reparationer ikke muligt
" #~ msgid "Initiating restart...
" #~ msgstr "Forbereder genstart...
" #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "Job \"%s\" er genoptaget i køen" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "Jobs markeret med '*' vil ikke blive hentet automatisk." #~ msgid "Not matched" #~ msgstr "Matchede ikke" #~ msgid "Downloaded so far" #~ msgstr "Hentet indtil videre" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Kan ikke tilslutte til registreringsdatabasen HKEY_CURRENT_USER." #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Kan ikke åbne nøgle i registreringsdatabasen \"%s\"." #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Kunne ikke læse nøgler i registreringsdatabasen for specielle mapper" #~ msgid "You have no permisson to use port %s" #~ msgstr "Du har ingen tilladelse til at bruge port %s" #~ msgid "Try again" #~ msgstr "Forsøg igen" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "pyopenssl modul mangler, du skal installere for HTTPS-adgang" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Manglede forventet fil: %s => unrar fejl?" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "Udpakning mislykkedes, en ventet fil er ikke udpakket" #~ msgid "Main packet not found..." #~ msgstr "Hovedarkiv mangler..." #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Mislykkedes med importering af OpenSSL modul. Tilslutter uden SSL" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Det lykkedes ikke at fjerne nzo fra efterbehandlings køen (id)" #~ msgid "View script output" #~ msgstr "Vis script udlæsning" #~ msgid "Queued" #~ msgstr "Køen" #~ msgid "Complete Dir" #~ msgstr "Færdig download mappe" #~ msgid "Download speed" #~ msgstr "Download hastighed" #~ msgid "WARNINGS" #~ msgstr "ADVARSLER" #~ msgid "Add new downloads" #~ msgstr "Tilføj nye downloads" #~ msgid " or Report ID" #~ msgstr " eller Report ID" #~ msgid "Hide files" #~ msgstr "Skjul filer" #~ msgid "Show files" #~ msgstr "Vis filer" #~ msgid "Remain/Total" #~ msgstr "Tilbage/Totalt" #~ msgid "History Size" #~ msgstr "Størrelse af Historik" #~ msgid "Show Weblogging" #~ msgstr "Vis webblog" #~ msgid "Thread" #~ msgstr "Tråd" #~ msgid "Email Test Result" #~ msgstr "E-mail testresultat" #~ msgid "General configuration" #~ msgstr "Generel konfiguration" #~ msgid "Activate an alternative skin." #~ msgstr "Aktivere et alternativ udseende." #~ msgid "Web server authentication" #~ msgstr "Webserver godkendelse" #~ msgid "Queue auto refresh interval:" #~ msgstr "Automatisk opdaterings interval af kø:" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "opdaterings interval af kø-siden (sek, 0= ingen)." #~ msgid "Disable API-key" #~ msgstr "Deaktivere API-nøgle" #~ msgid "Do not require the API key." #~ msgstr "Kræver ingen API-nøgle." #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "ANDVEND PÅ EGEN RISIKO!" #~ msgid "Folder configuration" #~ msgstr "Mappe konfiguration" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Efterbehandlings scripts mappe" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "Mappe, der indeholder bruger scripts til efterbehandling." #~ msgid "Switches configuration" #~ msgstr "Parameterkonfiguration" #~ msgid "Processing Switches" #~ msgstr "Forløbs parameter" #~ msgid "Enable Quick Check" #~ msgstr "Aktiver hurtig tjek" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Spring par2 kontrol over, når filerne er 100% gyldige." #~ msgid "Enable built-in unzip functionality." #~ msgstr "Aktivere indbygget Unzip funktion." #~ msgid "Enable Filejoin" #~ msgstr "Aktiver Fil Sammenføjning (Filejoin)" #~ msgid "Enable TS Joining" #~ msgstr "Aktivere TS Sammenføjning (TS Joining)" #~ msgid "Enable Par Cleanup" #~ msgstr "Aktiver Par rensning (Par Cleanup)" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Oprydning af par filer (hvis kontrollerede / reparation lykkedes)." #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Ved fejl på yEnc CRC" #~ msgid "Default Post-Processing" #~ msgstr "Standard efterbehandling" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "Anvedes når efterbehandlingen er bestemt efter kategori." #~ msgid "Default User Script" #~ msgstr "Standard bruger scripts" #~ msgid "Used when no user script is defined by the category." #~ msgstr "Anvendes når bruger scripts er bestemt efter kategori." #~ msgid "Default Priority" #~ msgstr "Standard prioritet" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Anvendes når ingen prioritet er bestemt af kategori." #~ msgid "Enable MultiCore Par2" #~ msgstr "Aktivere MultiCore Par2" #~ msgid "Other Switches" #~ msgstr "Andre parameter" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Erstat ugyldige tegn i mappenavn." #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Erstat ugyldige tegn i mappenavn med modsvarende tegn (ellers fjern)." #~ msgid "Do not download" #~ msgstr "Download ikke." #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Anvend V23 hvis ikke din leverandør (ISP) kræver andet!" #~ msgid "Server configuration" #~ msgstr "Serverkonfiguration" #~ msgid "Click below to test." #~ msgstr "Klik nedenfor for at teste." #~ msgid "Scheduling configuration" #~ msgstr "Planlægningskonfiguration" #~ msgid "RSS Configuration" #~ msgstr "RSS-konfiguration" #~ msgid "Delete Feed" #~ msgstr "Fjern Feeds" #~ msgid "Email Options" #~ msgstr "E-mail alternativ" #~ msgid "Email Account Settings" #~ msgstr "E-mail kontoinstillinger" #~ msgid "User-defined categories" #~ msgstr "Bruger definerede kategorier" #~ msgid "Defines post-processing and storage." #~ msgstr "Definerer post-behandling og opbevaring." #~ msgid "Sorting configuration" #~ msgstr "Sorteringskonfiguration" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Aktiverer sortering og omdøbning af episoder." #~ msgid "Generic Sorting" #~ msgstr "Almindelig sortering" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Aktiverer sortering og omdøbning af filer." #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Aktivere hvis ikke download er flyttet til egen mappe." #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Aktiverer sortering og omdøbning af datomarkeret filer." #~ msgid "Are you sure you want to delete" #~ msgstr "Er du sikker på at du vil slette" #~ msgid "Page" #~ msgstr "Side" #~ msgid "Close" #~ msgstr "Luk" #~ msgid "Pause for 12 hours" #~ msgstr "Pause 12 timer" #~ msgid "Pause for 24 hours" #~ msgstr "Pause 24 timer" #~ msgid "Open Source URL" #~ msgstr "Åbn kildekode URL" #~ msgid "Storage" #~ msgstr "Opbevaring" #~ msgid "Access" #~ msgstr "Adgang" #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "Jeg ønsker at SABnzbd skal være synlige fra enhver pc på netværket." #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Jeg ønsker kun at SABnzbd skal være synlige fra min computer." #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Aktiver HTTPS-adgang til SABnzbd." #~ msgid "Misc" #~ msgstr "Diverse" #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "Start webbrowseren med SABnzbd's siden når programmet startes." #~ msgid "Please enter a whole number." #~ msgstr "Angiv et helt tal." #~ msgid "Step One" #~ msgstr "Trin et" #~ msgid "Step Two" #~ msgstr "Trin to" #~ msgid "Step Three" #~ msgstr "Trin tre" #~ msgid "Step Four" #~ msgstr "Trin fire" #~ msgid "Step Five" #~ msgstr "Trin fem" #~ msgid "KB/s" #~ msgstr "KB/s" #~ msgid " " #~ msgstr " " #~ msgid "Secondary Web Interface" #~ msgstr "Sekundær udseende" #~ msgid "HTTPS Support" #~ msgstr "HTTPS Support" #~ msgid "SSL type" #~ msgstr "SSL type" #~ msgid "Backup server" #~ msgstr "Backup server" #~ msgid "Remove" #~ msgstr "Slet" #~ msgid "Skip" #~ msgstr "Spring over" #~ msgid "New Feed URL" #~ msgstr "Ny Feed URL" #~ msgid "Set Pause Interval" #~ msgstr "Sæt pause interval" #~ msgid "Pause Interval" #~ msgstr "Pause interval" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Upload: .nzb .rar .zip .gz" #~ msgid "Hour:Min" #~ msgstr "Time:Minut" #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "Efter SABnzbd har genstartet vil du være i stand til at få adgang til det på " #~ "følgende placering: %s" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd er ikke kompatibel med visse software firewalls.
\n" #~ " %s
\n" #~ " Beklager, men vi kan ikke løse denne uforenelighed lige nu.
\n" #~ " Du kan indsende en klage til din firewall leverandør.
\n" #~ "
\n" #~ msgid "OK" #~ msgstr "OK" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd brug for en ledig TCP / IP-port til sin intern webserver .
\n" #~ " Port %s på %s blev forsøgt , men den konto, der anvendes til SABnzbd har " #~ "ikke tilladelse til at bruge det.
\n" #~ " På OSX og Linux systemer, skal brugere normalt bruge porte over " #~ "1023.
\n" #~ "
\n" #~ " Venligst genstart SABnzbd med et andet port nummer." #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Det er sandsynligt, at du bruger ZoneAlarm på Vista .
" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Udpakning mislykkedes, disse fil (er) mangler:" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Brug 12 timers ur (AM / PM)" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Vis tider i AM / PM notation (påvirker ikke skemalægger)." #~ msgid "folder" #~ msgstr "mappe" #~ msgid "Original Foldername" #~ msgstr "Orginal Mappenavn" #~ msgid "Groups / Indexer tags" #~ msgstr "Gruppe / Index tags" #~ msgid "Server definition" #~ msgstr "Server definition" #~ msgid "Delete all failed items from History?" #~ msgstr "Slet alle mislykkedes emner fra historie?" #~ msgid "Purge Failed History" #~ msgstr "Rens mislykket historie" #~ msgid "Feeds" #~ msgstr "Feeds" #~ msgid "Add Feed" #~ msgstr "Tilføj feed" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "Anvend backup-server ved yEnc CRC fejl." #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Læs Feedhenter det nuværende feed indholdet. Tving " #~ "hent vil hente alle matchende NZBs nu." #~ msgid "Settings" #~ msgstr "Indstillinger" #~ msgid "Get NZB" #~ msgstr "Hent NZB" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "F.eks. 119 eller 563 for SSL" #~ msgid "Filters" #~ msgstr "Filtre" #~ msgid "Check result of unpacking" #~ msgstr "Tjek resultat af udpakning" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Tjek resultat af udpakning (skal være slukket for nogle filsystemer)." #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "Sammenføjer filer, der ender med .001, .002 osv. til en fil." #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "Sammenføjer filer, der ender med, 001.ts, .002.ts osv. til en fil." #~ msgid "Only for optional servers" #~ msgstr "Kun for ekstra servere" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Påfør maksimalt antal forsøg kun til valgfri servere" #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Ugyldig PAR2 filer, kan ikke kontrollere eller reparere" #~ msgid "QR Code" #~ msgstr "QR kode" #~ msgid "Notification classes" #~ msgstr "Notification klasser" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "" #~ "Aktiver klasser af meddelelser der skal indberettes (ingen, én eller flere)" #~ msgid "Refer to https://www.oznzb.com/profile" #~ msgstr "Se https://www.oznzb.com/profile" #~ msgid "Site API Key" #~ msgstr "Sidens API nøgle" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Denne nøgle kobler profilen til indekseringen. Se " #~ "https://www.oznzb.com/profile." #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Udvidet funktioner inklusiv anmeldelser og ekstra status information bliver " #~ "tilgængelige hvis forbundet med OZnzb indekseringen." #~ msgid "Enable OZnzb Integration" #~ msgstr "Aktiver OZnzb integration" #~ msgid "OZnzb" #~ msgstr "OZnzb" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "" #~ "Send automatisk kalkuleret validerings resultater for downloads til " #~ "indekseringen." #~ msgid "Automatic Feedback" #~ msgstr "Automatisk tilbagemelding" #~ msgid "Sort by name" #~ msgstr "Sortér efter navn" #~ msgid "Sort by age" #~ msgstr "Sortér efter alder" #~ msgid "Sort by size" #~ msgstr "Sortér efter størrelse" #~ msgid "Enable built-in unrar functionality." #~ msgstr "Aktivér indbygget Unrar funktion." #~ msgid "Enable Unrar" #~ msgstr "Aktivér Unrar" #~ msgid "Left" #~ msgstr "Venstre" #~ msgid "Plush Options" #~ msgstr "Plush Indstillinger" #~ msgid "This field is required." #~ msgstr "Dette felt er påkrævet." #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "ADVARSEL: Jobbet er afbrudt \" %s\" på grund af krypteret RAR fil" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "ADVARSEL: Jobbet er sat på pause \"%s\" på grund af krypteret RAR fil" #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Beskyt adgangen med kodeord til SABnzbd (anbefales)" SABnzbd-2.3.2/po/main/de.po0000644000000000000000000047346713217005051013440 0ustar 00000000000000# German translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2017-10-10 19:03+0000\n" "Last-Translator: Robin Munkittrick \n" "Language-Team: German \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:30+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "MultiPar Programmdatei nicht gefunden!" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Fehler beim Starten der Weboberfläche." #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "" "Konnte Web-Vorlage nicht finden: %s Versuche die Standard-Vorlage zu " "verwenden." #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" "SABYenc deaktiviert: Keine korrekte Version gefunden! (Gefunden v%s, " "Erwartet v%s)" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" "SABYenc Modul... Nicht gefunden! Erwarte v%s - https://sabnzbd.org/sabyenc" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "_yenc-Modul nicht gefunden!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "par2-Programmdatei nicht gefunden!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "Überprüfung und Reparatur sind nicht möglich." #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" "Deine UNRAR-Version ist %s, Wir empfehlen Version %s oder höher.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "Downloads werden nicht enpackt." #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "unrar-Programmdatei nicht gefunden!" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "unzip-Programmdatei nicht gefunden!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "7za-Programmdatei nicht gefunden" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Bitte beachten Sie, dass der 0.0.0.0-Hostname eine IPv6-Adresse benötigen " "wird für den externen Zugriff." #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "HTTP und HTTPS Ports dürfen nicht Identisch sein!" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" "SABnzbd wurde mit Encoder/Zeichensatz %s gestartet, Dieser sollte UTF-8 " "sein. Es werden Probleme mit Unicode codierten Dateien und " "Ordnerbezeichnungen in Downloads erwartet." #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "HTTPS wegen fehlenden Zertifikats- und Schlüsseldateien deaktiviert." #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Fehler beim Starten der Web-Oberfläche " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "SABHelper-Dienst kann nicht erreicht werden" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s gestartet" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Achtung" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Fehler" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "SABnzbd wurde beendet" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Der Hostname wurde nicht angegeben" #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "" "Keine Verbindungen angegeben. Bitte geben Sie mindestens eine Verbindung ein." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Passwort ist als ****** maskiert. Bitte erneut eingeben." #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Ungültige Server-Angaben" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "" "Zeitüberschreitung: Versuchen Sie, SSL oder einen anderen Port zu verwenden." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Zeitüberschreitung" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" "Unbekanntes SSL-Protokoll: SSL deaktivieren oder alternativen Port versuchen." #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Ungültige Server-Adresse." #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Sever beendet beim Anmeldeverlauf." #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Server benötigt ein Benutzername und ein Passwort." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Verbindung erfolgreich hergestellt!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "" "Authentifizierung fehlgeschlagen. Überprüfen Sie Benutzername und Passwort." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "Zu viele Verbindungen. Bitte halten Sie die Downloads an oder versuchen Sie " "es später erneut." #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Die Verbindung konnte nicht überprüft werden. (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Signal %s erkannt. Wird gespeichert und beendet …" #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Schwerer Fehler beim Speichern des Zustands" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "NZB-Datei wird versucht von %s abzurufen" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Fehler beim Speichern von %s" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Temporäre Datei für %s konnte nicht angelegt werden" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Status für nicht vorhandenen Server wird versucht %s einzustellen" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Fehler in tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Fehler beim Laden von %s" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Laden von %s ist mit Fehler %s fehlgeschlagen" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Benachrichtigungen testen" #: sabnzbd/api.py msgid " Resolving address" msgstr " Adresse wird aufgelöst …" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Nichts" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Standard" #: sabnzbd/api.py msgid "unknown" msgstr "unbekannt" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "" "Kompilieren des regulären Ausdrucks für den Suchbegriff %s fehlgeschlagen." #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "Angehalten wegen zu wenig freiem Speicherplatz" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Festplatte voll! Downloads werden angehalten." #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Festplattenfehler beim Anlegen der Datei %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Schwerer Fehler im Assembler" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" "ACHTUNG: \"%s\" wurde angehalten, da es ein verschlüsseltes RAR Archiv " "enthält (falls unterstützt, wurden alle Passwörter ausprobiert)" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" "ACHTUNG: \"%s\" wurde abgebrochen, da es ein verschlüsseltes RAR Archiv " "enthält (falls unterstützt, wurden alle Passwörter ausprobiert)" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Abgebrochen, Verschlüsselung vorhanden" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "WARNUNG: Unerwünschter Typ \"%s\" in RAR Datei. Unerwünschte Datei ist %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "Unerwünschter Dateityp in rar-Archiv %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Abgebrochen, unerwünschte Dateieindung gefunden" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "WARNUNG: Job \"%s\" aufgrund der Bewertung (%s) pausiert." #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "Warnung: Aufgabe \"%s\" aufgrund der Bewertung (%s) abgebrochen" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Abbruch, Bewertungsfilter stimmt überein (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s fehlt" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" "Aufgabe \"%s\" ist wahrscheinlich verschlüsselt, RAR hat den gleichen Namen " "wie das gepackte RAR-Archiv" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" "Aufgabe \"%s\" ist wahrscheinlich verschlüsselt: \"Passwort\" im Dateiname " "\"%s\"" #: sabnzbd/assembler.py msgid "video" msgstr "Video" #: sabnzbd/assembler.py msgid "audio" msgstr "Audio" #: sabnzbd/assembler.py msgid "spam" msgstr "Spam" #: sabnzbd/assembler.py msgid "passworded" msgstr "passwortgeschützt" #: sabnzbd/assembler.py msgid "downvoted" msgstr "als schlecht bewertet" #: sabnzbd/assembler.py msgid "keywords" msgstr "Schlüsselwörter" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Kontingent aufgebraucht, Downloads werden angehalten" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s ist keine gültige E-Mail-Adresse" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Server-Adresse wird benötigt" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Kann kein %s Ordner %s erstellen" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Kann INI-Datei %s nicht schreiben" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Kann keine Sicherungsdatei erstellen für %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Ungültig kodiertes Passwort %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s ist kein gültiger Oktal-Wert" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "UNC-Pfad \"%s\" ist hier nicht erlaubt" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Fehler: Dateipfadlänge sollte kürzer als %s sein." #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "" "Fehler: Ordner kann nicht geändert werden, da die Warteschlange nicht leer " "ist." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "" "Kann nicht in die Verlaufsdatenbank schreiben, überprüfe die Zugriffsrechte!" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "Verlaufsdatenbank geschädigt, eine leere neue wurde erstellt" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "SQL-Befehl fehlgeschlagen. Beachten Sie das Nachrichtenprotokoll." #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "" "Fehler beim Schliessen der Datenbank. Beachten Sie das Nachrichtenprotokoll." #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Ungültiges Stufen-Protokoll im Verlauf für %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Fehler beim Dekodieren von %s." #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "Decoder Fehler: Nicht genügend Speicher" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Ungültiger yEnc-Artikel in %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Unbekannter Fehler %s beim Dekodieren" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "UUencode gefunden, nur yEnc Codierung wir unterstützt [%s]" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s wurde auf keinem Server gefunden und daher übersprungen" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "Direkt entpacken" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Fertiggestellt" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "%s Datei(en)/Ordner entpackt in %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "Direkt entpacken wurde automatisch aktiviert" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" "Aufträge werden bereits während des Download-Vorgangs entpackt, um die " "Nachbearbeitungszeit zu verkürzen. Nur für Aufträge, die nicht repariert " "werden müssen." #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "%s kann nicht gelesen werden" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Fehler beim Hinzufügen von %s. Entferne." #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Fehler beim Entfernen von %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Überwachter Ordner %s kann nicht gelesen werden" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Fortgesetzt" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Angehalten" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Bevor ein Bandbreitenlimit gesetzt werden kann, muss die maximale Bandbreite " "festgelegt werden" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Server %s wird für %s Minuten ignoriert" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Fehler %s@%s zu initialisieren, aus folgendem Grund: %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "Zu viele Verbindungen zu Server %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Möglicherweise wird das Konto geteilt" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Anmelden beim Server fehlgeschlagen. %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Verbindung zum Server %s kann nicht hergestellt werden. %s" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "Fehler beim Verbinden mit %s@%s, Meldung = %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Server %s benötigt ein Benutzername und ein Passwort" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Vermute Fehler im Downloader" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Wird beendet …" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Verbindung zum Mail-Server konnte nicht hergestellt werden" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "Aufbau der TLS-Verbindung fehlgeschlagen" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "Keine korrekte Server-Antwort auf den HELO/EHLO-Check" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Authentifizierung beim Mail-Server fehlgeschlagen" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Keine passende Authentifizierungsmethode gefunden" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "Unbekannter Authentifizierungsfehler des E-Mail-Servers" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Senden des E-Mails fehlgeschlagen" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Schliessen der Mail-Verbindung fehlgeschlagen" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "E-Mail erfolgreich versendet" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Absenden nicht möglich, benötigte Daten fehlen" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "In %s konnten keine E-Mail-Vorlagen gefunden werden" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Keine E-Mail gesendet da keine Empfänger angegeben" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Ungültige Kodierung der E-Mail-Vorlage %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Keine E-Mail-Vorlagen gefunden" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd meldet eine volle Festplatte\n" "\n" "Hallo,\n" "\n" "SABnzbd hat mit dem Herunterladen aufgehört, da die Festplatte fast voll \"\n" "ist.\n" "Bitte geben Sie manuell Speicherplatz frei und setzen Sie die Downloads \"\n" "danach fort.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "" "Warnung: localhost ist mehrdeutig. Verwenden Sie eine numerische IP-Adresse." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Server-Adresse \"%s:%s\" ist ungültig." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "Benutzer im Web-Interface angemeldet" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "Benutzer angemeldet" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Sitzungs-Schlüssel fehlt" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Fehler: Sitzungsschlüssel wird benötigt" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Fehler: Sitzungsschlüssel ungültig" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "API-Schlüssel fehlt. Bitte API-Schlüssel aus Einstellungen->Allgemein in die " "externe Anwendung eingeben:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "API-Schlüssel ungültig. Bitte API-Schlüssel aus Einstellungen->Allgemein in " "die externe Anwendung eingeben:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Authentifizierung fehlt. Bitte Benutzernamen und Passwort aus Einstellungen-" ">Allgemein in die externe Anwendung eingeben:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Probier' den neuen Skin Glitter! Er bietet ein frisches, für PC und " "Mobilgeräte optimiertes Erlebnis. Einstellen über Konfiguration -> Allgemein." #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "Fehlerhafter Login Versuch von %s" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
SABnzbd wurde beendet.
Warten Sie 5 Sekunden und klicken Sie " "danach auf folgenden Knopf.

Aktualisieren
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Feed" #: sabnzbd/interface.py msgid "Daily" msgstr "Täglich" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "Montag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Dienstag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Mittwoch" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Donnerstag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Freitag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Samstag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Sonntag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "Aus" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Undefinierter Server!" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Fehlerhafter Parameter" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Zurück" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "FEHLER:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Fehlerhafter Wert für %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "t" #: sabnzbd/misc.py msgid "h" msgstr "h" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Verzeichnis %s konnte nicht angelegt werden" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "Zugriff auf das Verzeichnis %s fehlgeschlagen: %s" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Erstellen von %s fehlgeschlagen" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Verschieben von %s nach %s fehlgeschlagen" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Fehler beim Anlegen des SSL-Schlüssels und -Zertifikats." #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" "Ihre Passwort-Datei enthält mehr als 30 Passwörter, das Testen aller " "Passwörter dauert sehr lange. Versuchen Sie, nur nützliche Passwörter " "aufzulisten." #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Rechte von %s konnten nicht geändert werden" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Ausführen des Skripts" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Nachbearbeitung wurde abgebrochen (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Skript" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Entpacken zu tief verschachtelt [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Zusammenfügen" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Unvollständiger Ablauf beim zusammenführen von Dateien" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Fehler beim Zusammenfügen von %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Fehler \"%s\" beim Zusammenfügen der Dateien" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Fehler \"%s\" beim Ausführen von file_join auf %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] %s Dateien zusammengefügt" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Entpacken fehlgeschlagen. %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Fehler \"%s\" beim Entpacken der RAR-Dateien" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Fehler \"%s\" beim Ausführen von rar_unpack auf %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Löschen von %s fehlgeschlagen!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Versuche entpacken mit Passwort \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Entpacken fehlgeschlagen. Archiv benötigt ein Passwort." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Entpacken" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Entpacken" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Entpacken fehlgeschlagen. Konnte %s nicht finden." #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "FEHLER: »%s« kann nicht gefunden werden." #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Entpacken fehlgeschlagen. CRC-Fehler" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "FEHLER: CRC in »%s« fehlgeschlagen." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" "Entpacken fehlgeschlagen - Datei zu groß für Dateisystem (Formatierung FAT?)" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "Fehler: Datei zu groß für Dateisystem (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "" "Entpacken fehlgeschlagen. Fehler beim Schreiben oder volle Festplatte?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "FEHLER: Schreibfehler %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Entpacken fehlgeschlagen, Pfad ist zu lang" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "FEHLER: Pfad ist zu lang (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Entpacken fehlgeschlagen. Beachten Sie das Protokoll." #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "FEHLER: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "RAR-Datei beschädigt" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "Defekte RAR Datei" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s Dateien in %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Fehler \"%s\" beim Ausführen von unzip auf %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Versuche 7zip mit Passwort \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "Das 7zip-Set \"%s\" ist unvollständig, kann nicht entpackt werden" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Konnte nicht entpacken %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Schnelle Überprüfung" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Reparieren" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Schnelle Überprüfung erfolgreich" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Beginn der Reparatur" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "" "Par-Verifikation für \"%s\" fehlgeschlagen, obwohl der QuickCheck " "erfolgreich war" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Reparatur fehlgeschlagen. %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Fehler \"%s\" beim Ausführen von par2_repair auf %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Fehler \"%s\" beim Ausführen von par2_repair auf dem Satz %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] Ungültige PAR2-Optionen. Überprüfen Sie die Angaben in Einstellungen -> " "Schalter." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Überprüft in %s. Alle Dateien fehlerfrei." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Überprüft in %s. Reparatur wird benötigt." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" "Ungültige par2-Dateien oder ungültige PAR2-Parameter, Auftrag konnte nicht " "überprüft oder repariert werden" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "%s Blöcke werden abgerufen …" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Abrufen" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "" "Reparatur fehlgeschlagen. Nicht genug Reparatur-Blöcke vorhanden (%s zu " "wenig)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Reparieren" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Repariert in %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "Überprüfe Reparatur" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Festplatte voll" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Überprüfen" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "Überprüfe zusätzliche Dateien" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Wird überprüft" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "Dem Pythonskript \"%s\" fehlen die Ausführungsrechte (+x)" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Dieser Server erlaubt kein SSL auf diesem Port" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" "Zertifikat ungültig: Der Server-Host ist nicht im angegeben Zertifikat " "enthalten. Dies ist ein Serverproblem." #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" "Zertifikat ist nicht gültig. Dies ist wahrscheinlich ein Serverproblem." #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "Der Server %s verwendet ein nicht vertrauenswürdiges Zertifikat [%s]" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Starten/Beenden" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "Hinzugefügte NZB" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Nachbearbeitung gestartet" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Auftrag ausgeführt" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Auftrag fehlgeschlagen" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Warteschlange abgearbeitet" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Andere Nachrichten" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Nicht verfügbar" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Konnte Prowl-Nachricht nicht versenden" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Fehlerhafte Antwort von Pushbullet (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Konnte Pushover-Nachricht nicht versenden" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Fehlerhafte Antwort von Pushbullet (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Konnte Pushbullet-Nachricht nicht versenden" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "Skript gab Fehlercode %s und Ausgabe \"%s\" zurück" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "Benachrichtigungsskript \"%s\" existiert nicht" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "Windows Benachrichtigung konnte nicht gesendet werden" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "" "Alte Warteschlangen-Version erkannt, über Status->Reparieren ins neue Format " "konvertieren" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "" "Inkompatible Warteschlangen-Datei gefunden. Fortsetzen nicht möglich." #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Fehler beim Laden von %s. Beschädigte Datei gefunden." #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "NZB konnte nach Vorab-Check nicht neugestartet werden (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB zur Warteschlange hinzugefügt" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Unbekannte Kodierung" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Die Datei %s ist leer und wird daher übersprungen" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Importieren von %s Dateien von %s fehlgeschlagen" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Unvollständige NZB-Datei %s" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Ungültige NZB-Datei %s wird übersprungen: %s auf Zeile %s" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Leere NZB-Datei %s" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" "Das Vorwarteschlangen (pre-queue) Skript hat die Downloadaufgabe als " "gescheitert markiert" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Doppelte NZB \"%s\" wird ignoriert" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "kopieren der NZB \"%s\" fehlgeschlagen" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "Doppelte NZB" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Doppelt vorhandene NZB \"%s\" angehalten" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Abgebrochen, kann nicht fertiggestellt werden" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "DUPLIKAT" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "VERSCHLÜSSELT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "ZU GROSS" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "UNVOLLSTÄNDIG" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "UNERWÜNSCHT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "GEFILTERT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "WARTE %s Sek" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "AUSBREITUNG %s min" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "" "Heruntergeladen in %s mit einer Durchschnittsgeschwindigkeit von %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Alter" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s Artikel hatten ein ungültiges Format" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s Artikel fehlten" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s Artikel hatten nicht übereinstimmende Duplikate" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s Artikel wurden entfernt" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Fehler beim Importieren von %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Warnungen" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Leerlauf" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Einstellungen" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Warteschlange" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Warteschlange leeren" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Verlauf" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Verlauf leeren" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Geschwindigkeit begrenzen" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Anhalten" #: sabnzbd/osxmenu.py msgid "min." msgstr "Min." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Fortsetzen" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Überwachter Ordner lesen" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Alle RSS-Feeds lesen" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Fertige Downloads" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Unfertige Download" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Fehler suchen" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Neu starten" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Neustart ohne Anmeldung" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Beenden" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Warteschlange mit den 10 obersten Einträgen" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Leer" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Verlauf mit den letzten 10 Einträgen" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Neue Version verfügbar" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Assistent öffnen" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Wird angehalten …" #: sabnzbd/panic.py msgid "Problem with" msgstr "Problem mit" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " Für seinen internen Web-Server benötigt SABnzbd einen freien TCP/IP-" "Port.
\n" " Port %s auf %s wurde probiert, ist aber nicht verfügbar.
\n" " Entweder verwendet eine andere Software den Port oder SABnzbd läuft " "bereits.
\n" "
\n" " Starten Sie SABnzbd bitte mit einer anderen Portnummer neu." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "" "Wenn Sie diesen Fehler wieder erhalten, probieren Sie eine andere Nummer.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " Für seinen internen Web-Server benötigt SABnzbd eine gültige Rechner-" "Adresse.
\n" " Sie haben eine ungültige Adresse angegeben.
\n" " Sichere Werte sind localhost und 0.0.0.0
\n" "
\n" " Starten Sie SABnzbd bitte mit einer gültigen Rechner-Adresse neu." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd hat die gespeicherten Daten einer anderen SABnzbd-Version " "erkannt,
\n" " kann diese aber nicht wiederverwenden.

\n" " Es wird empfohlen, die ausstehenden Downloads mit der anderen Version " "fertigzustellen.

\n" " Starten Sie dieses Programm danach mit der \"--clean\"-Option.
\n" " Dies löscht die Download-Warteschlange und den Download-Verlauf!
\n" " SABnzbd hat die Datei \"%s\" gelesen." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd kann die Dateien für die Web-Oberfläche in %s nicht finden.
\n" " Installieren Sie bitte das Programm erneut.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd hat einen schwerwiegenden Fehler erkannt:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd hat erkannt, dass die Datei sqlite3.dll fehlt.

\n" " Manche unausgereiften Viren-Scanner löschen diese Datei.
\n" " Bitte überprüfen Sie den Viren-Scanner, versuchen Sie eine " "Neuinstallation von SABnzbd und beschweren Sie sich beim Hersteller des " "Viren-Scanners.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Drücken Sie Start+R und geben Sie folgenden Zeile ein (Beispiel):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Öffnen Sie ein Terminal und geben Sie folgende Zeile ein (Beispiel):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Programm wurde nicht gestartet!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" "Konnte nicht an Port %s auf %s starten. Eine andere Software nutzt diesen " "Port oder SABnzbd läuft bereits." #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Schwerwiegender Fehler" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "" "Der Standard-Browser konnte nicht gestartet werden, da er wahrscheinlich " "nicht gefunden wurde." #: sabnzbd/panic.py msgid "Access denied" msgstr "Zugriff verweigert" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "" "Fehler %s: Sie müssen einen gültigen Benutzername und ein Passwort angeben." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" "Download-Ordner %s für abgeschlossene Downloads auf FAT Dateisystem, ist " "auf maximale Dateigröße von 4GB begrenzt." #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" "Modul subprocessww fehlt. Fehler mit Unikodierter Datei und Verzeichnisnamen " "in den Downloads sind zu erwarten." #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "" "Download wahrscheinlich fehlgeschlagen, nur %s von benötigten %s verfügbar" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Download fehlgeschlagen - Nicht auf deinem/n Server/n vorhanden" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Keine Nachbearbeitung wegen fehlgeschlagener Überprüfung" #: sabnzbd/postproc.py msgid "Moving" msgstr "Verschiebevorgang" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "%s wurde an die Warteschlange gesendet" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Fehler beim Umbenennen von \"%s\" nach \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Dateien verschieben fehlgeschlagen" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Ausführen des Benutzer-Skripts %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "%s ausgeführt" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Exit-Code des Skripts ist %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Mehr" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Nachbearbeitung von %s fehlgeschlagen (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "Beachten Sie die Protokolldatei" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Download Fehlgeschlagen" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Aufräumen von %s fehlgeschlagen" #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Fehler beim Entfernen des Arbeitsverzeichnisses %s." #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Download fertig" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Konnte Download-Ordner %s nicht anlegen" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Nachbearbeitung" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Keine PAR2-Sätze" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Versuche SFV-Überprüfung" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Überprüfung einiger Dateien mittels %s fehlgeschlagen" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Überprüfung mit SFV-Datei(en) erfolgreich" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "RAR-basierte Überprüfung versuchen" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "[%s] RAR-basierte Überprüfung ist fehlgeschlagen: %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "passwortgeschützt" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "RAR-Datei erfolgreich überprüft" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "RAR-Datei konnten nicht überprüft werden" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Entfernen von %s fehlgeschlagen" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Fehler beim Wechsel in den Ruhezustand" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Fehler beim Wechsel in den Bereitschaftsmodus" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Fehler beim Herunterfahren des Systems" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "Indexer ID (%s) für Bewertung nicht gefunden" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Server-Adresse" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "API-Schlüssel" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" "Der Schlüssel liefert die Identität des Indexers. Prüfe dein Profil auf der " "indexer Webseite." #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Ungültige RSS-Feed-Beschreibung \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Abrufen des RSS-Feeds von %s fehlgeschlagen: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Keine gültige Berechtigung für Feed %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "Server-Fehler (Code %s); konnte %s von %s nicht laden" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "Der Server %s nutzt ein nicht vertrauenswürdiges HTTPS-Zertifikat" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "RSS-Feed %s war leer" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Inkompatibeler RSS-Feed" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Leerer RSS-Feed gefunden: %s" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Interface anzeigen" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Öffne Zielverzeichnis" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Beenden" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Verbleibend" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "NZB hinzufügen" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Ungültige Regel %s um %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Unbekannte Aktion: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Regel für nicht existierenden Server %s." #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Herunterladen" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Dateien zusammenfügen" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Quelle" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Server" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Fehler" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Fehlgeschlagen" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "Warten" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Wird repariert …" #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Wird entpackt …" #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Wird verschoben …" #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Skripts wird ausgeführt …" #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Zusätzliche Blöcke werden abgerufen …" #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Schnelle Überprüfung …" #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Überprüfung läuft …" #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Am herunterladen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "Ausbreitungsverzögerung" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Häufigkeit" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Aktion" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Argumente" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Aufgabe" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "Server deaktivieren" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "Server aktivieren" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Geschwindigkeitsbegrenzung" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Alle anhalten" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Nachbearbeiten anhalten" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Nachbearbeiten fortsetzen" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "RSS-Feeds lesen" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Entferne fehlgeschlagene Aufträge" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Abgeschlossene Aufträge entfernen" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Aufträge mit niedriger Priorität pausieren" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Aufträge mit normaler Priorität pausieren" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Aufträge mit hoher Priorität pausieren" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Aufträge mit niedriger Priorität fortsetzen" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Aufträge mit normaler Priorität fortsetzen" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Aufträge mit hoher Priorität fortsetzen" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Quoten-Management einschalten" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Quoten-Management ausschalten" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "Aufträge mit Kategorie pausieren" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "Aufträge mit Kategorie fortsetzen" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Nein" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Sehr niedrig" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Mittel" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normal" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Hoch" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Notfall" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Gering" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "MB" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "GB" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "Stunde" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "Stunden" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "Minuten" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "Minuten" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "Sekunde" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "Sekunden" #: sabnzbd/skintext.py msgid "day" msgstr "Tag" #: sabnzbd/skintext.py msgid "days" msgstr "Tage" #: sabnzbd/skintext.py msgid "week" msgstr "Woche" #: sabnzbd/skintext.py msgid "Month" msgstr "Monat" #: sabnzbd/skintext.py msgid "Year" msgstr "Jahr" #: sabnzbd/skintext.py msgid "January" msgstr "Januar" #: sabnzbd/skintext.py msgid "February" msgstr "Februar" #: sabnzbd/skintext.py msgid "March" msgstr "März" #: sabnzbd/skintext.py msgid "April" msgstr "April" #: sabnzbd/skintext.py msgid "May" msgstr "Mai" #: sabnzbd/skintext.py msgid "June" msgstr "Juni" #: sabnzbd/skintext.py msgid "July" msgstr "Juli" #: sabnzbd/skintext.py msgid "August" msgstr "August" #: sabnzbd/skintext.py msgid "September" msgstr "September" #: sabnzbd/skintext.py msgid "October" msgstr "Oktober" #: sabnzbd/skintext.py msgid "November" msgstr "November" #: sabnzbd/skintext.py msgid "December" msgstr "Dezember" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Tag im Monat" #: sabnzbd/skintext.py msgid "This week" msgstr "Diese Woche" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Dieser Monat" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "Heute" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Gesamt" #: sabnzbd/skintext.py msgid "on" msgstr "An" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parameter" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Python Version" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Startseite" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "oder" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Adresse" #: sabnzbd/skintext.py msgid "Comment" msgstr "Kommentar" #: sabnzbd/skintext.py msgid "Send" msgstr "Absenden" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Abbrechen" #: sabnzbd/skintext.py msgid "Other" msgstr "Andere" #: sabnzbd/skintext.py msgid "Report" msgstr "Bericht" #: sabnzbd/skintext.py msgid "Video" msgstr "Video" #: sabnzbd/skintext.py msgid "Audio" msgstr "Audio" #: sabnzbd/skintext.py msgid "Not used" msgstr "Nicht verwendet" #: sabnzbd/skintext.py msgid "or less" msgstr "oder weniger" #: sabnzbd/skintext.py msgid "Log in" msgstr "Anmelden" #: sabnzbd/skintext.py msgid "Log out" msgstr "Abmelden" #: sabnzbd/skintext.py msgid "Remember me" msgstr "Automatische Anmeldung" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "Automatisiertes Programm für Usenet-Downloads" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Speichern" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Sind Sie sicher?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Alle heruntergeladenen Dateien löschen?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Startseite" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Einstellungen" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Status" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Hilfe" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Forum" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "Probleme" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "Bitte unterstützen Sie das Projekt durch eine Spende!" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Allgemein" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Ordner" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Schalter" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Planung" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Benachrichtigungen" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "E-Mail" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Kategorien" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Sortierung" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Spezial" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Suchen" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Downloads" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "ANGEHALTEN" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "%s Artikel im Cache (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Systemlast" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Neue Version %s verfügbar unter" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Möchten Sie SABnzbd wirklich beenden?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Hinzufügen einer" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Datei hinzufügen" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Kategorie" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Verarbeiten" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Priorität" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Reparieren" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Entpacken" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Löschen" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "E" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "L" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Erzwingen" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Anhalten" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "Wenn fertig" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Rechner ausschalten" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "Rechner in Bereitschaft versetzen" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Rechner in den Ruhezustand versetzen" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "SABnzbd beenden" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Geschwindigkeitsbegrenzung" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Anhalten für" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Reihenfolge" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Name" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "ETA" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "Alter" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Löschen" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Erneut versuchen" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Aktionen" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Skripte" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Alle Elemente in der Warteschlange löschen?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "NZBs löschen" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "NZBs und Dateien löschen" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Fehlgeschlagene Aufträge neustarten" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "NZB löschen" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "NZBs und Dateien löschen" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "von" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Fehlende Artikel" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Verbleibendes Kontingent" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "Manuell" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Kontingent jetzt zurücksetzen" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Alle fertigen Downloads aus dem Verlauf entfernen?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Details verbergen" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Details anzeigen" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Nur Fehlgeschlagene" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Alle anzeigen" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Grösse" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Fehlgeschlagene NZBs löschen" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Fehlgeschlagene NZBs und Dateien löschen" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Fertige NZBs löschen" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "Lösche NZBs auf der aktuellen Seite" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "Optionale ergänzende NZB-Datei" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Pfad" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Alle fehlgeschlagenen neustarten" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Alle neustarten" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus/Spam" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "Außerhalb der Serverretention" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Anderes Problem" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Verbindung trennen" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Sendet eine Test-E-Mail an Ihr Konto." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Protokoll anzeigen" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "E-Mail testen" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Protokoll" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Fehler/Warnungen" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ Info" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ Fehlersuche" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Verbindungen" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Neuste Warnungen" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "Leeren" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Freigeben" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Artikelbezeichner" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Dateimenge" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Wann" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Typ" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Aktiv" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Übersichtsseite" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Verbindung fehlgeschlagen!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Lokale IPv4-Adresse" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Öffentliche IPv4-Adresse" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "IPv6-Adresse" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "DNS-Server" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "CPU-Modell" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "System Performance" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Zielverzeichnis Geschwindigkeit" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Zielverzeichnis Geschwindigkeit" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Schreibgeschwindigkeit" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "Konnte nicht schreiben. Überprüfe, ob der Ordner beschreibbar ist." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Klick auf \"Test wiederholen\" um es festzustellen" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Test wiederholen" #: sabnzbd/skintext.py msgid "Config File" msgstr "Konfigurationsdatei" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Verwendeter Cache" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Ein Klick auf den Knopf \\\"Neu starten\\\" startet SABnzbd neu.
\r\n" "Benutzen Sie ihn, falls ein Stabilitätsproblem vorliegt.
\r\n" "Die Downloads werden vor dem Neustart angehalten und danach fortgesetzt." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" "
Wenn Anmeldung aktiviert ist, müssen sie sich danach noch mal anmelden." #: sabnzbd/skintext.py msgid "Advanced" msgstr "Erweitert" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Der Download-Ordner enthält verwaiste Aufträge.
Diese können gelöscht " "(zusammen mit den Dateien) oder zurück in die Warteschlange verschoben " "werden." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "Ein Klick auf den Knopf \"Reparieren\" startet SABnzbd neu
und baut die " "Warteschlange neu auf, wobei bereits
heruntergeladene Dateien bestehen " "bleiben. Die Reihenfolge
der Warteschlange wird dabei verändert." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Die Änderungen wurden nicht gespeichert und werden verloren gehen." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" "Falls sich deine IP Adresse ändert oder SABnzbd neu startet, wird deine " "Session ungültig" #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "unzip aktivieren" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "7zip aktivieren" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "Multicore Par2" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" "Sichere (SSL) Verbindungen von SABnzbd zu den Newsservern und HTTPS-" "Webseiten werden verschlüsselt, allerdings ist es nicht möglich die " "Identität eines Servers mittels Zertifikat zu bestätigen. Python 2.7.9 oder " "höher, OpenSSL 1.0.2 oder höher und aktuelle lokale CA certificate werden " "benötigt." #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" "Erhöhe Reparaturgeschwindigkeit durch installation von Multicore Par2, " "verfügbar auf vielen Plattformen." #: sabnzbd/skintext.py msgid "Version" msgstr "Version" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Zeit seit Start" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Sicherheitskopie" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Lesen Sie dazu die Hilfe im Wiki!" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "SABnzbd wird neu gestartet …" #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Änderungen benötigen einen Neustart von SABnzbd!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "SABnzbd-Webserver" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "SABnzbd-Host" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Host, auf dem SABnzbd auf Anfragen warten soll." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "SABnzbd-Port" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Port, auf dem SABnzbd auf Anfragen warten soll." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Web-Oberfläche" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Gestaltung der Web-Oberfläche verändern." #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "SABnzbd-Benutzername" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Optionale Anmeldung mit Benutzername" #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "SABnzbd-Passwort" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Optionale Anmeldung mit Passwort" #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" "Wenn der SABnzbd Host oder Port im Netz freigegeben ist, lassen die " "gegenwärtigen Einstellung vollen zugriff auf die SABnzbd Oberfläche zu." #: sabnzbd/skintext.py msgid "Security" msgstr "Sicherheit" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "HTTPS aktivieren" #: sabnzbd/skintext.py msgid "not installed" msgstr "nicht installiert" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Zugriff auf die Oberfläche über HTTPS-Adressen erlauben" #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "HTTPS-Port" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Wenn leer, hört der Standard-Port nur auf HTTPS-Anfragen." #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "HTTPS-Zertifikat" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Dateiname oder Pfad des HTTPS-Zertifikats." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" "Neues selbstzertifiziertes Zertifikat und Schlüssel generieren. SABnzbd muss " "neugestartet werden!" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "HTTPS-Schlüssel" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Dateiname oder Pfad des HTTPS-Schlüssels." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "HTTPS-Kette Zertifikat" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Dateiname oder Pfad zur HTTPS-Kette." #: sabnzbd/skintext.py msgid "Tuning" msgstr "Feinabstimmung" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "RSS-Überprüfung" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Überprüfungs-Intervall (in Minuten, mindestens 15). Nicht aktive wenn Regeln " "aktiv sind!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Maximale Downloadgeschwindigkeit" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Prozentsatz der Downloadgeschwindigkeit" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "" "Welchen Prozentsatz deiner Downloadgeschwindigkeit SABnzbd nutzen soll, z.B. " "50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Begrenzung des Artikel-Caches" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Artikel werden zwischengespeichert, um die Anzahl der Zugriffe auf die " "Festplatte zu reduzieren.
In Bytes, gefolgt von einem optionalen K, " "M oder G. Zum Beispiel: \"64M\" oder \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Unerwünschte Dateien" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Liste der Dateiendungen, die nach dem Download gelöscht werden sollen.
Zum Beispiel:nfo or nfo,sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "Verlaufsgröße" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" "Fertige Aufträge automatisch aus dem Verlauf entfernen. Duplikatserkennung " "und manche externe Skripte benötigen Informationen aus dem Verlauf." #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "Alle Aufträge behalten" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "Behalte maximale Anzahl an abgeschlossenen Aufträgen" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "Behalte abgeschlossene Aufträge maximal X Tage" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "Fertige Aufträge nicht behalten" #: sabnzbd/skintext.py msgid "Jobs" msgstr "Aufträge" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Änderungen speichern" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "Werkseinstellung wiederherstellen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Zurücksetzen" #: sabnzbd/skintext.py msgid "Language" msgstr "Sprache" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Wählen Sie die Sprache der Weboberfläche." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" "Hilf uns beim Übersetzen von SABnzbd in deiner Sprache!
Neue " "Übersetzungen hinzufügen oder bestehende verbessern kannst du hier:" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "" "Dieser Schlüssel gibt Drittprogrammen uneingeschränkten Zugriff auf SABnzbd." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "NZB-Schlüssel" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "Dieser Schlüssel erlaubt Drittprogrammen das Hinzufügen von NZB-Dateien zu " "SABnzbd." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Neuen Schlüssel generieren" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "API-Key OR-Code" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Liste der lokalen Netzwerkadressenbereiche" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Alle lokalen Netzwerkadressen starten mit diesen Präfixen (oft " "\"192.168.1.1\")" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Externer Internetzugriff" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" "Du kannst Zugriffsrechte für Systeme ausserhalb deines Netzwerkes setzen. " "Benötigt die Definition einer Liste von lokalen Netzwerkbereichen." #: sabnzbd/skintext.py msgid "No access" msgstr "Kein Zugriff" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "NZB Dateien hinzufügen " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (kein Einstellungen)" #: sabnzbd/skintext.py msgid "Full API" msgstr "Ganze API" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Volles Webinterface" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "Nur externer Zugriff benötigt eine Anmeldung" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "HINWEIS: Ordner werden beim Speichern automatisch erstellt. Sie " "können absolute Pfade angeben, um Ordner ausserhalb der standardmässigen " "Ordner zu verwenden." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Benutzer-Ordner" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Durchsuchen" #: sabnzbd/skintext.py msgid "In" msgstr "In" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Temporärer Download-Ordner" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Hier werden noch nicht verarbeitete Downloads abgelegt.
Kann nur " "geändert werden wenn die Warteschlange leer ist." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Minimaler freier Speicherplatz im temporären Ordner" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "SABnzbd hält automatisch an, wenn der freie Speicherplatz unter diesen Wert " "fällt.
In Bytes, gefolgt von einem optionalen K, M oder G. Zum " "Beispiel: \"800M\" or \"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Ordner für fertige Downloads" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Hier werden fertige, verarbeitete Downloads abgelegt.
Kann von " "benutzerdefinierten Kategorien ausser Kraft gesetzt werden." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Rechte für fertige Downloads" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Rechte für Dateien und Ordner festlegen.
In oktaler Notation. Zum " "Beispiel: \"755\" oder \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Überwachter Ordner" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Ordner, der auf neue NZB-Dateien überwacht werden soll.
Erkennt auch " "ZIP-, RAR- und TAR.GZ-Archive mit NZB-Dateien." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Geschwindigkeit der Ordner-Überwachung" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Anzahl der Sekunden zwischen zwei Überprüfungen." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "Skript Ordner" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "Ordner enthält Benutzer Skripte" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Ordner mit E-Mail-Vorlagen" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Ordner, der benutzerdefinierte E-Mail-Vorlagen enthält." #: sabnzbd/skintext.py msgid "Password file" msgstr "Passwortdatei" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Datei mit allen Passwörtern, die bei verschlüsselten RAR-Dateien probiert " "werden sollen." #: sabnzbd/skintext.py msgid "System Folders" msgstr "System-Ordner" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Administrativer Ordner" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Ordner, der die für die Warteschlange und den Verlauf verwendeten " "Datenbanken enthält.
Kann nur geändert werden, wenn die " "Warteschlange leer ist." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "Es werden keine Dateien entfernt. Benötigt einen Neustart von " "SABnzbd!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Protokoll-Ordner" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Hier werden Protokoll-Dateien von SABnzbd abgelegt.
Benötigt einen " "Neustart von SABnzbd!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr "NZB-Backup-Ordner" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Hier werden NZB-Dateien abgelegt." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Standardmässiger Basis-Ordner" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Alle Par2-Dateien herunterladen" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" "Dies verhindert mehrfache Reparaturversuche, durch herunterladen aller par2 " "Dateien, wenn notwendig." #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Rekursives Entpacken aktivieren" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Archive (rar, zip, 7z) innerhalb von Archiven entpacken." #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Alle Ordner innerhalb Archiven ignorieren" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Alle Dateien werden in einen einzelnen Ordner gespeichert." #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Nur Artikel für obersten Warteschlangen-Eintrag herunterladen" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Für geringere Speicher-Verwendung aktivieren.
Deaktivieren, um zu " "verhindern, dass langsame Aufträge
die anderen Einträge in der " "Warteschlange blockieren." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Nur überprüfte Aufträge nachbearbeiten" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "" "Die Nachbearbeitung nur für Aufträge durchführen,
die alle PAR2-" "Überprüfungen bestanden haben." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Aktion wenn eine verschlüsselte RAR Datei geladen wird" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "Im Fall von \"Pause\" müssen Sie ein Kennwort setzen und den Job fortsetzen." #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Doppelte Downloads erkennen" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" "Doppelte NZB Datei entdeckt (basierend auf den Eintragungen in der Historie " "oder den .nzb Dateien im NZB-Backup-Ordner)" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Doppelte Episoden in Serien erkennen" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" "Identische Episoden in den Serien entdeckt (basierend auf " "\"name/season/episode\") der Einträge in der Historie" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "Erlaube \"Proper\" Releases" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" "Umgehe Serien Duplikat-Erkennung, wenn PROPER, REAL oder REPACK im Download-" "Namen erkannt wird" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Verwerfen" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "Aufgabe abgebrochen (verschoben in die Historie)" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "Markiere Auftrag" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Abbrechen" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Aktion bei ungewollter Dateienendung" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "Aktion bei ungewollter Dateiendung innerhalb RAR-Archiven" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Ungewollte Dateiendungen" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Liste aller ungewollter Dateiendungen. Zum Beispiel: exe or exe, " "com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "SFV-basierte Überprüfung aktivieren" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Zusätzliche Überprüfung mittels SFV-Dateien durchführen" #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Benutzerskript kann Auftrag als fehlgeschlagen markieren" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Wenn das Benutzerskript einen Exit-Code ausgibt, der nicht \"0\" ist, wird " "der Auftrag als fehlgeschlagen markiert." #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "Nach einem Fehler ein alternatives NZB laden" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "" "Manche Server stellen ein alternatives NZB zur Verfügung, falls ein Download " "fehlschlägt." #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "Übernehme Markierungen vom Indexer" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" "Beim Sortieren, verwende Tags aus Indexer für Titel, Saison, Episode, usw. " "Andernfalls wird alle Namensgebung aus dem NZB-Namen abgeleitet." #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Ordner-Umbenennung aktivieren" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Temporäre Namen während der Nachbearbeitung verwenden. Deaktivieren, wenn " "das System nicht damit klar kommt." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Benutzer-Skript vor Warteschlange" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "" "Wird verwendet, bevor eine NZB-Datei zur Warteschlange hinzugefügt wird." #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Zusätzliche PAR2-Parameter" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Nice-Parameter" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "IONice-Parameter" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Bei leerer Warteschlange Verbindung trennen" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "" "Verbindung zu Usenet-Servern trennen,
wenn die Warteschlange leer ist " "oder SABnzbd angehalten wurde." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Nach Alter sortieren" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "" "Einträge automatisch nach ihrem (durchschnittlichen) Alter sortieren." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" "Artikel werden angehalten bis sie mindestens das gewählte alter erreicht " "haben. Ändern der Job Priorität auf Erzwingen wird die Verzögerung " "überspringen." #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Auf neue Version prüfen" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Wöchentlich überprüfen, ob eine neue SABnzbd-Version verfügbar ist." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "Auch Test-Veröffentlichungen" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Leerzeichen in Ordnernamen ersetzen" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Leerzeichen in Ordnernamen durch Unterstriche ersetzen." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Punkte in Ordner-Namen ersetzen" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Punkte in Ordner-Namen durch Leerzeichen ersetzen." #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Für Windows kompatibel machen" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "" "Für Server: stell sicher, dass die Dateinamen mit Windows kompatibel sind." #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Browser beim Start öffnen" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Den Standard-Browser öffnen, wenn SABnzbd gestartet wird." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Downloads während der Nachbearbeitung anhalten" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Hält die Downloads zu Beginn der Nachbearbeitung an
und setzt sie " "danach fort." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Beispieldateien ignorieren" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Beispieldateien herausfiltern (z.B. Videoausschnitte)" #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Nach dem Download löschen" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "HTTPS Zertifikat Überprüfung" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" "Überprüfe Zertifikate bei Verbindungen zu Indexern und RSS-Quellen über " "HTTPS." #: sabnzbd/skintext.py msgid "Server" msgstr "Server" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Nachbearbeitung" #: sabnzbd/skintext.py msgid "Naming" msgstr "Benennung" #: sabnzbd/skintext.py msgid "Quota" msgstr "Kontingent" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indexierung" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Wie viel kann in diesem Monat heruntergeladen werden (K/M/G)?" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Tag zurücksetzen" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "An welchem Tag des Monats oder der Woche (1=Montag) setzt Ihr ISP das " "Kontingent zurück (optional mit hh:mm)?" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Automatisch fortsetzen" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "" "Soll wieder Heruntergeladen werden, nachdem das Kontingent zurückgesetzt " "wurde?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Kontingents-Periode" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "" "Wird das Kontingent jeden Tag, jede Woche oder jeden Monat zurückgesetzt?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Vor dem Herunterladen überprüfen" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Versuche die erfolgreiche Fertigstellung noch vor dem Herunterladen " "vorherzusagen (langsamer!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "SSL-Verschlüsselung" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" "Die Performanz verbessern, indem eine schwächere SSL-Verschlüsselung " "erzwungen wird." #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Maximale Wiederholungen" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Maximale Anzahl wiederholter Versuche pro Server" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Aufträge abbrechen, die nicht abgeschlossen werden können" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Job abbrechen falls während des Downloads klar wird, dass zuviele Daten " "fehlen" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "Indexer Integration eingeschaltet" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" "Indexer können Rating Informationen liefern, wenn ein Job hinzugefügt wird " "und SABnzbd kann dem Indexer melden, wenn ein Job nicht abgeschlossen werden " "konnte." #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Filter aktivieren" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Action-Downloads nach Filterregeln." #: sabnzbd/skintext.py msgid "Abort If" msgstr "Abbrechen wenn" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Andererseits pausieren wenn" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Videobewertung" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Audiobewertung" #: sabnzbd/skintext.py msgid "Spam" msgstr "Spam" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Bestätigt" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Mehr Daumen-Hoch als -Runter" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Titel-Schlüsselwörter" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Durch Komma getrennte Liste" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Server Lastverteilung" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Lastverteilung verhindern" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Lastverteilung zulassen" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Lastverteilung mit IPv6-Optimierung zulassen" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "Nützlich, wenn ein Newsserver mehr als eine IPv4/IPv6-Adresse hat" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Server hinzufügen" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Serverbeschreibung" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Port" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Benutzername" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Passwort" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Zeitüberschreitung" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Rückhaltezeit" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "Sichere Verbindung zum Server" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "Zertifikat überprüfung" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" "Minimum: Wenn SSL aktiviert, prüft die Serveridentität und Benutzung seiner " "Zertifikate. Strikt: Prüft und stelle sicher das der Hostname stimmt." #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Deaktiviert" #: sabnzbd/skintext.py msgid "Minimal" msgstr "Minimum" #: sabnzbd/skintext.py msgid "Strict" msgstr "Strikt" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 ist die höchste, 100 die niedrigste Priorität" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Optional" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "Für unzuverlässige Server, wird bei Fehlern länger ignoriert" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Aktivieren" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Server entfernen" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Server überprüfen" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Zähler zurücksetzen" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Server-Angaben werden überprüft …" #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Bandbreite" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Gruppe senden" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Gruppen-Befehl senden, bevor Artikeln angefordert werden." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Diesen Server nur für diese Kategorien benutzen." #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" "Keiner der aktivierten Server hat die \"Standard\" Kategorie ausgewählt. " "Jobs in der Warteschlange die nicht mit einer Server Kategorie verbunden " "sind werden nicht Heruntergeladen." #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Persönliche Notizen" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Regel hinzufügen" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Aktuelle Regeln" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "Aktivieren Sie das Feld neben dem Feed-Namen, wenn automatisch auf neue " "Einträge geprüft werden soll.
Wenn ein Feed hinzugefügt wird, werden " "nur neue Einträge verarbeitet und nicht diejenigen, die bereits im RSS-Feed " "enthalten waren, ausser Sie klicken \"Download erzwingen\"." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "Trenne verschiedene URLs mit Komma" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Feed lesen" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Download erzwingen" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Filter" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Akzeptieren" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Verwerfen" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Benötigt" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "Benötigt Kategorie" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Mindestens" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Höchstens" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "Von SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "Von Show SxxEyy" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Entspricht" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Entspricht nicht" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Heruntergeladen" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Jetzt alle Feeds lesen" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "Email-Benachrichtigung beim Fertigstellen von Aufträgen" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Nie" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Immer" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Nur bei Fehlern" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Benachrichtigung bei voller Festplatte" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "" "E-Mail senden, wenn die Festplatte voll ist und SABnzbd angehalten wird." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "RSS-Benachrichtigungen senden" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "" "E-Mail senden, wenn ein RSS-Feed einen Auftrag zur Warteschlange hinzufügt." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "SMTP-Server" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "ISP-Server für ausgehende E-Mails angeben." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "E-Mail-Empfänger" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "E-Mail-Adresse, an die die E-Mails gesendet werden." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "E-Mail-Absender" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Wer soll die E-Mail versandt haben?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "Optionaler Konto-Benutzername" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Für authentifizierte E-Mails wird der Kontoname benötigt." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "Optionales Konto-Passwort" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Für authentifizierte E-Mails wird das Passwort benötigt." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Growl aktivieren" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Benachrichtigungen an Growl senden" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Nur für entfernten Growl-Server verwenden (Rechnername:Port)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Server-Passwort" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Optionales Passwort für den Growl-Server" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "NotifyOSD aktivieren" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Benachrichtigungen an NotifyOSD senden" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Benachrichtigungscenter" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Benachrichtigung an Benachrichtigungscenter schicken" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Windows-Benachrichtigungen aktivieren" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Windows-Benachrichtigungen" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Prowl-Benachrichtigungen aktivieren" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Benötigt einen Prowl-Account" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "API-Schlüssel für Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Dein API-Key für Prowl (benötigt)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Pushover-Benachrichtungen aktivieren" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Benötigt einen Pushover-Account" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Applikationstoken" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Applikationstoken (benötigt)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Benutzer-Schlüssel" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Benutzer-Schlüssel (benötigt)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Gerät(e)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Geräte, welche die Nachrichten empfangen sollen" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "Wie oft die selbe benachrichtigung (in Sekunden) geschickt wird." #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Pushbullet-Benachrichtigungen aktivieren" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Benötigt einen Pushbullet-Account" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Persönlicher API-Key" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Dein Pushbullet API-Key (benötigt)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Gerät" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Geräte, welche die Benachrichtigungen empfangen sollen" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "Benachrichtigungs-Skript" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "Aktiviere Benachrichtigungs-Skript" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "Führt ein benutzerdefiniertes Skript aus" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "Welches Skript sollte für die Benachrichtigung ausgeführt werden" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" "Indexer können eine Kategorie innerhalb des NZB liefern, welche SABnzbd " "versuchen wird, mit den unten definierten Kategorien entsprechen. Darüber " "hinaus kannst du Begriffe zu \"Indexer Kategorien / Gruppen\" hinzufügen, um " "mehreren Kategorien zu entsprechen. Verwende Kommas, um Begriffe zu trennen. " "Wildcards in den Begriffen werden unterstützt.
Weitere Informationen " "können im Wiki gefunden werden." #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Ein Sternchen * am Pfad-Ende verhindert die Erzeugung von Auftrags-Ordnern." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Relative Ordner basieren auf" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Ordner/Pfad" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "Indexer Kategorien/Gruppen" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Sortieren von TV-Serien" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "TV-Sortierung aktivieren" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Muster-Schlüssel" #: sabnzbd/skintext.py msgid "Clear" msgstr "Löschen" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "Filter übernehmen" #: sabnzbd/skintext.py msgid "Presets" msgstr "Voreinstellungen" #: sabnzbd/skintext.py msgid "Example" msgstr "Beispiel" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "Film Sortierung" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Film-Sortierung aktivieren" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Unbestimmte Downloads in einem zusätzlichen Ordner speichern." #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Betroffene Kategorien" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Bedeutung" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Muster" #: sabnzbd/skintext.py msgid "Result" msgstr "Resultat" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Staffel-Ordner" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Staffel-Ordner" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Episoden-Ordner" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Episoden-Ordner" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Titel" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Film Name" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Film.Name" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Film_Name" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Sendungs Name" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Sendungs.Name" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Sendungs_Name" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Staffel-Nummer" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Episoden-Nummer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Episoden-Name" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Episoden.Name" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Episoden_Name" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Dateiendung" #: sabnzbd/skintext.py msgid "Extension" msgstr "Endung" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Teilnummer" #: sabnzbd/skintext.py msgid "Decade" msgstr "Jahrzehnt" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Ursprünglicher Dateiname" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Kleinschreibung" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEXT" #: sabnzbd/skintext.py msgid "text" msgstr "text" #: sabnzbd/skintext.py msgid "file" msgstr "Datei" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Sortieranweisung" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Markierung für mehrere Teile" #: sabnzbd/skintext.py msgid "In folders" msgstr "In Ordnern" #: sabnzbd/skintext.py msgid "No folders" msgstr "Keine Ordner" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Sortieren nach Datum" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Sortieren nach Datum aktivieren" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Ordner mit Name der Sendung" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "Jahr-Monat-Ordner" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Tägliche Ordner" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "Groß- / Kleinschreibung berücksichtigen" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Ergebnis" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Selten genutzte Funktionen. Bedeutung und Erklärungen finden Sie per klick " "auf den Hilfe-Button um auf die Wiki-Seite zu gelangen.
Änder nichts ohne " "vorher das Wiki gelesen zu haben, da sonst schwerwiegende Nebeneffekte " "auftreten können.
Die Ursprungswerte stehen zwischen den runden Klammern." #: sabnzbd/skintext.py msgid "Values" msgstr "Werte" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "NZB-Details bearbeiten" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Löschen" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Ganz nach oben" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Nach oben" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Nach unten" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Ganz nach unten" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Alle" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Invertieren" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Dateiname" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Betreff" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Auswahl" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "5 Minuten anhalten" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "15 Minuten anhalten" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "30 Minuten anhalten" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Eine Stunde anhalten" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "3 Stunden anhalten" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "6 Stunden anhalten" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "rest" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Freier Speicherplatz" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Temporärer Ordner" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Mehrfach-Funktionen" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Shift-Taste gedrückt halten, um einen ganzen Bereich auszuwählen" #: sabnzbd/skintext.py msgid "Check all" msgstr "Alle auswählen" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "SABnzbd neustarten" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Status und Interface-Optionen" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Oder Dateien per Drag-und-Drop ins Fenster ziehen!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Verbindung zu SABnzbd verloren.." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "" "Wenn SABnzbd neustartet, wird diese Anzeige automatisch verschwinden!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "WARNUNG:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Abrufen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Aktualisierungsrate" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "die globalen Interface-Einstellungen verwenden" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Limit der Objekte in der Warteschlange" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Limit der Objekte im Verlauf" #: sabnzbd/skintext.py msgid "Date format" msgstr "Datumsformat" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Extra Warteschlangen-Spalte" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "Extra Verlauf-Spalte" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "Seite" #: sabnzbd/skintext.py msgid "Loading" msgstr "Wird geladen..." #: sabnzbd/skintext.py msgid "articles" msgstr "Artikel" #: sabnzbd/skintext.py msgid "Rename" msgstr "Umbenennen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Reparatur der Warteschlange" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Aktive Verbindungen anzeigen" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Verwaiste Aufträge" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Zurück in die Warteschlange schicken" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Alle löschen" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Alle wiederholen" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "NZB aus URL laden" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "NZB hochladen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Wahlweise einen Dateinamen angeben:" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Formate: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Senden" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Open Informational-URL" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Versendet. Danke!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Nichts ausgewählt!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Alle ausgewählten Dateien entfernen" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Vollendete Dateien anzeigen/verstecken" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Skript-Protokoll anzeigen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Neue Version verfügbar!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" "Lokale Speicherung (cookies) sind in ihrem Browser Deaktiviert, Oberflächen " "Einstellungen gehen Verloren wenn sie den Browser schließen." #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "Glitter hat ein paar (neue) Feature die du bestimmt magst!" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Benutzerdefiniert" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "Kompaktes Layout" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "Tab Layout
(separate Warteschlange und Verlauf)" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Geschwindigkeit" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Löschen von Downloads bestätigen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Löschen von Verlaufeinträgen bestätigen" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Wie lange oder bis wann möchtest du pausieren? (in Englisch!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Sorry, damit konnten wir nichts anfangen. Versuchs nochmal." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Anhalten für …" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Neu laden" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Sortieren nach Alter Älteste→Neuste" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Sortieren nach Alter Neuste→Älteste" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Sortieren nach Name A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Sortieren nach Name Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Sortieren nach Grösse Kleinste→Grösste" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Sortieren nach Grösse Grösste→Kleiste" #: sabnzbd/skintext.py msgid "Uploading" msgstr "Wird hochgeladen" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "Erzwinge Trennung" #: sabnzbd/skintext.py msgid "Removing job" msgstr "Entferne Job" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "Entferne Jobs" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Zurück" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Weiter" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Verlauf wirklich leeren?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Sie müssen JavaScript aktivieren, damit Plush funktioniert!" #: sabnzbd/skintext.py msgid "Options" msgstr "Optionen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Wie viele Minuten angehalten werden soll." #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Hauptmenü" #: sabnzbd/skintext.py msgid "On Finish" msgstr "Wenn fertig" #: sabnzbd/skintext.py msgid "Sort" msgstr "Sortieren" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Sortieren nach Alter Älteste→Neuste" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Sortieren nach Alter Neuste→Älteste" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Sortieren nach Name A→Z" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Sortieren nach Name Z→A" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Sortieren nach Grösse Kleinste→Grösste" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Sortieren nach Grösse Grösste→Kleiste" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Warteschlange leeren?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Alle fehlgeschlagenen Aufträge im Verlauf wiederholen?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Leeren" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Maximale
Geschwindigkeit" #: sabnzbd/skintext.py msgid "Range" msgstr "Bereich" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Auf Auswahl anwenden" #: sabnzbd/skintext.py msgid "Everything" msgstr "Alles" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Aktualisierungsrate" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Breite" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "" "Verhindert, dass die Inhalte aktualisiert werden, wenn sich der Mauszeiger " "über der Warteschlange befindet." #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Aktualisierung durch Mauszeiger verhindern" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Hochladen" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Hochladen: .nzb .rar .zip .gz .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Fortschritt" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Nicht genug freier Speicherplatz für fertige Downloads!" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Freier Speicherplatz (Ordner mit temporären Dateien)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "LEERLAUF" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Downloads" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Fertige entfernen" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "" "Möchten Sie alle fehlergeschlagenen Downloads aus dem Verlauf löschen?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Fehlgeschlagene entfernen" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Alle fehlgeschlagenen Aufträge wiederholen?" #: sabnzbd/skintext.py msgid "Links" msgstr "Links" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Einträge %s bis %s von insgesamt %s werden angezeigt" #: sabnzbd/skintext.py msgid "No results" msgstr "Keine Ergebnisse" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Ein Resultat wird angezeigt" #: sabnzbd/skintext.py msgid "First" msgstr "Anfang" #: sabnzbd/skintext.py msgid "Last" msgstr "Ende" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "E-Mail gesendet!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Benachrichtigung gesendet!" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Speichervorgang …" #: sabnzbd/skintext.py msgid "Saved" msgstr "Gespeichert" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "NZB hinzufügen" #: sabnzbd/skintext.py msgid "DualView1" msgstr "DualView 1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "DualView 2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Möchten Sie SABnzbd wirklich neu starten?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Bearbeitungs-Einstellungen verbergen" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Bearbeitungs-Einstellungen anzeigen" #: sabnzbd/skintext.py msgid "Edit" msgstr "Bearbeiten" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Verbleibend" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "SABnzbd-Einrichtungsassistent" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "SABnzbd-Version" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Zurück" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Server-Details" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Geben Sie bitte die Informationen zu Ihrem Usenet-Provider an." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Die Anzahl der Verbindungen, die der Provider erlaubt." #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "Z.B. 8 oder 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Nur auswählen, wenn der Provider SSL-Verbindungen erlaubt." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Klicken um die eingegebenen Informationen zu überprüfen." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Z. B." #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "Die Einrichtung ist nun abgeschlossen." #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd läuft nun im Hintergrund." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "" "Das Schliessen des Browser-Fensters oder -Tabs beendet SABnzbd NICHT." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Es ist empfehlenswert, diese Seite mit einem Lesezeichen zu versehen und " "dieses verwenden, um SABnzbd aufzurufen, wenn es im Hintergrund läuft." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Weiterführende Informationen finden Sie in unserem" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "SABnzbd anzeigen" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "SABnzbd beenden" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Assistenten starten" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "Für SABnzbd besteht KEINERLEI GARANTIE.\n" "SABnzbd ist freie Software, die Sie unter bestimmten Bedingungen weitergeben " "dürfen.\n" "Sie steht unter der GNU GENERAL PUBLIC LICENSE Version 2 oder (nach Ihrer " "Option) jeder späteren Version.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "Um aus dem Usenet herunterladen zu können, benötigen Sie Zugriff auf einen " "Usenet-Provider. Ihr ISP bieten dies möglicherweise an, jedoch werden " "kostenpflichtige Provider empfohlen." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "Wenn Sie noch keinen Usenet-Provider haben, empfehlen wir Ihnen %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Fehler beim Abrufen der TV-Informationen: %s" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Umbenennen von %s nach %s fehlgeschlagen." #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Umbenennen der gleichen Datei von %s nach %s fehlgeschlagen." #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Konnte Servernamen nicht auflösen" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Unerlaubter Zugriff" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "Datei nicht auf dem Server" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "Server konnte nicht vollständig antworten" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "URLGRABBER abgestürzt" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Ungültige NZB-Datei." #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "Abrufen der URL fehlgeschlagen; %s" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "Ordner \"%s\" existiert nicht" #~ msgid "SQL Commit Failed, see log" #~ msgstr "SQL-Commit fehlgeschlagen. Beachten Sie das Nachrichtenprotokoll." #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "CRC-Fehler in %s (%s -> %s)" #~ msgid "Error: No secondary interface defined." #~ msgstr "Fehler: Keine sekundäre Oberfläche angegeben." #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Das verwendete UNRAR-Programm wird nicht empfohlen. Laden Sie UNRAR " #~ "stattdessen herunter von http://www.rarlab.com/rar_add.htm
" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "" #~ "Kein UNRAR-Programm gefunden. Das Entpacken von RAR-Dateien ist nicht " #~ "möglich
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "Kein PAR2-Programm gefunden. Eine Reparatur ist nicht möglich
" #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "Auftrag \"%s\" wurde wieder zur Warteschlange hinzugefügt" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "" #~ "Aufträge, die mit '*' markiert sind, werden nicht automatisch " #~ "heruntergeladen." #~ msgid "Not matched" #~ msgstr "Entspricht nicht" #~ msgid "Downloaded so far" #~ msgstr "Bis jetzt heruntergeladen" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "" #~ "Verbindung zu Registry-Umgebung HKEY_CURRENT_USER konnte nicht hergestellt " #~ "werden." #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Registry-Schlüssel %s konnte nicht geöffnet werden." #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Lesen der Registry-Schlüssel für spezielle Ordner fehlgeschlagen." #~ msgid "You have no permisson to use port %s" #~ msgstr "Sie haben nicht die Berechtigung, Port %s zu verwenden" #~ msgid "Try again" #~ msgstr "Erneut versuchen" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "pyopenssl-Modul fehlt. Bitte installieren für SSL-Unterstützung." #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Erwartete Datei %s nicht gefunden. Unrar-Fehler?" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "Entpacken fehlgeschlagen. Eine erwartete Datei wurde nicht entpackt." #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "" #~ "Fehler beim Importieren des OpenSSL-Moduls. Stelle Verbindung ohne SSL her." #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "" #~ "Fehler beim Entfernen der NZB-Datei von der Nachbearbeitungs-Warteschlange " #~ "(id)" #~ msgid "View script output" #~ msgstr "Skript-Ausgabe anzeigen" #~ msgid "Queued" #~ msgstr "In der Warteschlange" #~ msgid "Complete Dir" #~ msgstr "Fertige Downloads" #~ msgid "Download speed" #~ msgstr "Geschwindigkeit" #~ msgid "WARNINGS" #~ msgstr "WARNUNGEN" #~ msgid "Add new downloads" #~ msgstr "Neue Downloads hinzufügen" #~ msgid " or Report ID" #~ msgstr " oder Report-ID" #~ msgid "Sort by name" #~ msgstr "Nach Name sortieren" #~ msgid "Sort by age" #~ msgstr "Nach Alter sortieren" #~ msgid "Hide files" #~ msgstr "Dateien verbergen" #~ msgid "Show files" #~ msgstr "Dateien anzeigen" #~ msgid "Remain/Total" #~ msgstr "Verbleibend/Insgesamt" #~ msgid "History Size" #~ msgstr "Grösse des Verlaufs" #~ msgid "Show Weblogging" #~ msgstr "Web-Protokoll anzeigen" #~ msgid "Email Test Result" #~ msgstr "Resultat des E-Mail-Tests" #~ msgid "General configuration" #~ msgstr "Allgemeine Einstellungen" #~ msgid "Secondary Web Interface" #~ msgstr "Sekundäre Weboberfläche" #~ msgid "Activate an alternative skin." #~ msgstr "Gestaltung der sekundären Web-Oberfläche verändern." #~ msgid "Web server authentication" #~ msgstr "Authentifizierung für Web-Server" #~ msgid "HTTPS Support" #~ msgstr "HTTPS-Unterstützung" #~ msgid "Queue auto refresh interval:" #~ msgstr "Warteschlange automatisch neu laden" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "" #~ "Zeitintervall zwischen dem erneuten Laden der Warteschlange (in Sekunden). 0 " #~ "schaltet die Funktion ab." #~ msgid "Disable API-key" #~ msgstr "API-Key deaktivieren" #~ msgid "Do not require the API key." #~ msgstr "Keinen API-Schlüssel verwenden." #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "AUF EIGENE GEFAHR VERWENDEN!" #~ msgid "Folder configuration" #~ msgstr "Ordner-Einstellungen" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Ordner mit Nachbearbeitungs-Skripts" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "" #~ "Ordner, der benutzerdefinierte Skripts für die Nachbearbeitung von Downloads " #~ "enthält." #~ msgid "Switches configuration" #~ msgstr "Verschiedene Schalter" #~ msgid "Processing Switches" #~ msgstr "Verarbeitungs-Schalter" #~ msgid "Enable Quick Check" #~ msgstr "Schnelle Überprüfung aktivieren" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "PAR2-Überprüfung überspringen, wenn die Dateien 100% korrekt sind." #~ msgid "Enable Unrar" #~ msgstr "unrar aktivieren" #~ msgid "Enable built-in unrar functionality." #~ msgstr "Eingebaute Entpack-Funktion für RAR-Archive aktivieren." #~ msgid "Enable built-in unzip functionality." #~ msgstr "Eingebaute Entpack-Funktion für ZIP-Archive aktivieren." #~ msgid "Enable Filejoin" #~ msgstr "Zusammenfügen von Dateien aktivieren" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "" #~ "Dateien, die mit .001, .002 usw. enden, zu einer Datei zusammenfügen." #~ msgid "Enable TS Joining" #~ msgstr "Zusammenfügen von TS-Dateien aktivieren" #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "" #~ "Dateien, die mit .001.ts, .002.ts usw. enden, zu einer Datei zusammenfügen." #~ msgid "Enable Par Cleanup" #~ msgstr "PAR-Dateien aufräumen" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "" #~ "PAR-Dateien entfernen, wenn die Überprüfung und Reparatur erfolgreich war." #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "yEnc-CRC-Fehler nicht ignorieren" #~ msgid "Default Post-Processing" #~ msgstr "Standardmässige Nachbearbeitung" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "" #~ "Wird verwendet, wenn die Kategorie keine Nachbearbeitung vorschreibt." #~ msgid "Default User Script" #~ msgstr "Standardmässiges Benutzer-Skript" #~ msgid "Used when no user script is defined by the category." #~ msgstr "Wird verwendet, wenn die Kategorie kein Benutzer-Skript vorschreibt." #~ msgid "Default Priority" #~ msgstr "Standardmässige Priorität" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Wird verwendet, wenn die Kategorie keine Priorität vorschreibt." #~ msgid "Enable MultiCore Par2" #~ msgstr "Mehrkernprozessor-Unterstützung von PAR2 verwenden" #~ msgid "Other Switches" #~ msgstr "Andere Schalter" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Ungültige Zeichen in Ordnernamen ersetzen" #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Ungültige Zeichen in Ordnernamen durch äquivalente Zeichen ersetzen
(oder ansonsten entfernen)." #~ msgid "Do not download" #~ msgstr "Nicht herunterladen" #~ msgid "SSL type" #~ msgstr "SSL-Typ" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "V23 verwenden, ausser wenn der Provider etwas anderes benötigt." #~ msgid "Server configuration" #~ msgstr "Server-Einstellungen" #~ msgid "Backup server" #~ msgstr "Ersatz-Server" #~ msgid "Click below to test." #~ msgstr "Unten Klicken zum Überprüfen." #~ msgid "Scheduling configuration" #~ msgstr "Planung" #~ msgid "Remove" #~ msgstr "Entfernen" #~ msgid "RSS Configuration" #~ msgstr "RSS-Einstellungen" #~ msgid "New Feed URL" #~ msgstr "Neue Feed-URL" #~ msgid "Delete Feed" #~ msgstr "Feed löschen" #~ msgid "Email Options" #~ msgstr "Email-Optionen" #~ msgid "Email Account Settings" #~ msgstr "E-Mail-Kontoeinstellungen" #~ msgid "User-defined categories" #~ msgstr "Benutzerdefinierte Kategorien" #~ msgid "Defines post-processing and storage." #~ msgstr "Beeinflusst die Nachbearbeitung und Speicherung von Downloads." #~ msgid "Sorting configuration" #~ msgstr "Sortier-Einstellungen" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Sortieren und Umbenennen von Episoden aktivieren." #~ msgid "Generic Sorting" #~ msgstr "Allgemeines Sortieren" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Allgemeines Sortieren und Umbenennen von Dateien aktivieren." #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "" #~ "Aktivieren, wenn Downloads nicht in ihre eigenen Ordner abgelegt werden." #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "" #~ "Sortieren und Umbenennen von Dateien mit Daten im Dateinamen aktivieren." #~ msgid "Are you sure you want to delete" #~ msgstr "Möchten Sie wirklich löschen" #~ msgid "Page" #~ msgstr "Seite" #~ msgid "Close" #~ msgstr "Schliessen" #~ msgid "Set Pause Interval" #~ msgstr "Eine bestimmte Zeit lang anhalten" #~ msgid "Pause Interval" #~ msgstr "Anhalten" #~ msgid "Pause for 12 hours" #~ msgstr "12 Stunden anhalten" #~ msgid "Pause for 24 hours" #~ msgstr "24 Stunden anhalten" #~ msgid "Left" #~ msgstr "Verbleibend" #~ msgid "Open Source URL" #~ msgstr "Open Source-URL" #~ msgid "Storage" #~ msgstr "Speicherort" #~ msgid "Plush Options" #~ msgstr "Plush-Einstellungen" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Hochladen: .nzb .rar .zip .gz" #~ msgid "Hour:Min" #~ msgstr "Stunde:Min" #~ msgid "Access" #~ msgstr "Zugriff" #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "Alle Rechner in meinem Netzwerk sollen auf SABnzbd zugreifen können." #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Passwortgeschützter Zugriff auf SABnzbd (empfohlen)" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Zugriff auf SABnzbd über HTTPS ermöglichen" #~ msgid "Misc" #~ msgstr "Verschiedenes" #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "SABnzbd in meinem Webbrowser öffnen, wenn es gestartet wird." #~ msgid "This field is required." #~ msgstr "Dieses Feld wird benötigt." #~ msgid "Please enter a whole number." #~ msgstr "Bitte geben Sie eine ganze Zahl ein." #~ msgid "Step One" #~ msgstr "Schritt 1" #~ msgid "Step Two" #~ msgstr "Schritt 2" #~ msgid "Step Three" #~ msgstr "Schritt 3" #~ msgid "Step Four" #~ msgstr "Schritt 4" #~ msgid "Step Five" #~ msgstr "Schritt 5" #~ msgid "KB/s" #~ msgstr "KB/s" #~ msgid " " #~ msgstr " " #~ msgid "Thread" #~ msgstr "Thread" #~ msgid "Skip" #~ msgstr "Überspringen" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd funktioniert nicht in Kombination mit manchen Software-" #~ "Firewalls.
\n" #~ " %s
\n" #~ " Dieses Problem können Sie zur Zeit nicht selber lösen.
\n" #~ " Beschweren Sie sich bitte beim Hersteller der Firewall.
\n" #~ "
\n" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " Für seinen internen Web-Server benötigt SABnzbd einen freien TCP/IP-" #~ "Port.
\n" #~ " Port %s auf %s wurde probiert, aber das für SABnzbd verwendete Konto " #~ "darf ihn nicht verwenden.
\n" #~ " Auf OS X und Linux-Systemen müssen normale Benutzer Ports über 1023 " #~ "verwenden.
\n" #~ "
\n" #~ " Starten Sie SABnzbd bitte mit einer anderen Portnummer neu." #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Sie verwenden wahrscheinlich ZoneAlarm auf Vista.
" #~ msgid "OK" #~ msgstr "OK" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Entpacken fehlgeschlagen. Diese Dateien fehlten:" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "12-Stunden-Uhr verwenden (AM/PM)" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Zeiten in der AM/PM-Notation anzeigen (betrifft die Regeln nicht)." #~ msgid "folder" #~ msgstr "Ordner" #~ msgid "Original Foldername" #~ msgstr "Ursprünglicher Ordnername" #~ msgid "Groups / Indexer tags" #~ msgstr "Gruppen/Indexer-Tags" #~ msgid "Server definition" #~ msgstr "Server-Definition" #~ msgid "Delete all failed items from History?" #~ msgstr "Alle fehlgeschlagenen Downloads aus dem Verlauf entfernen?" #~ msgid "Purge Failed History" #~ msgstr "Fehlgeschlagene aus Verlauf entfernen" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "Bei yEnc-CRC-Fehlern Ersatz-Server verwenden." #~ msgid "Feeds" #~ msgstr "Feeds" #~ msgid "Add Feed" #~ msgstr "Feed hinzufügen" #~ msgid "Settings" #~ msgstr "Einstellungen" #~ msgid "Get NZB" #~ msgstr "NZB abrufen" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Feed lesen ruft den momentanen Inhalt des Feeds ab. " #~ "Download erzwingen lädt sogleich alle passenden NZB-Dateien " #~ "herunter." #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "Z.B. 119 oder 563 für SSL" #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Ungültige PAR2-Dateien. Überprüfung oder Reparatur nicht möglich." #~ msgid "Filters" #~ msgstr "Filter" #~ msgid "Only for optional servers" #~ msgstr "Nur für optionale Server" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Die Anzahl Wiederholungen nur auf optionale Server anwenden" #~ msgid "Check result of unpacking" #~ msgstr "Resultat des Entpackens überprüfen" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Resultat des Entpackens überprüfen (muss bei manchen Dateisystemen " #~ "deaktiviert sein)." #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Nur mein Rechner soll auf SABnzbd zugreifen können." #~ msgid "Sort by size" #~ msgstr "Nach Größe sortieren" #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "Nach dem Neustart von SAbnzbd können Sie über folgende Adresse darauf " #~ "zugreifen: %s" #~ msgid "QR Code" #~ msgstr "QR-Code" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "WARNUNG: Job \"%s\" abgebrochen wegen verschlüsselter RAR Datei" #~ msgid "Notification classes" #~ msgstr "Benachrichtigungsarten" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "" #~ "Benachrichtigung für Nachrichtengruppen aktivieren (keine, eine oder " #~ "mehrere)" #~ msgid "Main packet not found..." #~ msgstr "Hauptpaket nicht gefunden …" #~ msgid "Initiating restart...
" #~ msgstr "Neustart wird durchgeführt …
" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "" #~ "Automatisch berechnete Validierungsergebnisse deiner Downloads zum Indexer " #~ "übermitteln." #~ msgid "Automatic Feedback" #~ msgstr "Automatisches Feedback" #~ msgid "Site API Key" #~ msgstr "API-Schlüssel deines OZnzb-Accounts" #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Der OZnzb-Indexer stellt erweiterte Funktionalitäten inkl. Bewertungen und " #~ "extra Statusinformationen zur Verfügung." #~ msgid "Enable OZnzb Integration" #~ msgstr "OZnzb-Integration aktivieren" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Dieser Schlüssel identifiziert dich gegenüber des Indexers. Siehe auch " #~ "https://www.oznzb.com/profile." SABnzbd-2.3.2/po/main/en.po0000644000000000000000000000746413217004754013451 0ustar 00000000000000# English corrections for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2015-07-04 10:12+0000\n" "PO-Revision-Date: 2015-07-04 12:26+0000\n" "Last-Translator: shypike \n" "Language-Team: Dutch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "Pause low prioirty jobs" msgstr "Pause low priority jobs" msgid "Pause normal prioirty jobs" msgstr "Pause normal priority jobs" msgid "Pause high prioirty jobs" msgstr "Pause high priority jobs" msgid "Resume low prioirty jobs" msgstr "Resume low priority jobs" msgid "Resume normal prioirty jobs" msgstr "Resume normal priority jobs" msgid "Resume high prioirty jobs" msgstr "Resume high priority jobs" msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
SABnzbd shutdown finished.
Wait for about 5 seconds and then " "click the button below.

Refresh
" msgid "Retry all failed" msgstr "Retry All Failed" msgid "disable server" msgstr "Disable server:" msgid "enable server" msgstr "Enable server:" msgid "The server didn't reply properly to the helo greeting" msgstr "The server didn't reply properly to the hello greeting" msgid "API Key missing, please enter the api key from Config->General into your 3rd party program:" msgstr "API key missing, please enter the API key from Config->General into your 3rd party program:" msgid "API Key incorrect, Use the api key from Config->General in your 3rd party program:" msgstr "API key incorrect, Use the API key from Config->General in your 3rd party program:" msgid "HTTPS Chain Certifcates" msgstr "HTTPS Chain Certificates" msgid "Replace Spaces in Foldername" msgstr "Replace spaces in folder name" msgid "Replace dots in Foldername" msgstr "Replace dots in folder name" msgid "How long or untill when do you want to pause? (in English!)" msgstr "How long or until when do you want to pause? (in English!)" msgid "Timeleft" msgstr "Time left" msgid "Optionally specify a filename" msgstr "Optionally specify a name" msgid "Confirm Queue Deletions" msgstr "Confirm queue deletions" msgid "Confirm History Deletions" msgstr "Confirm history deletions" msgid "System Performance (Pystone)" msgstr "System performance (Pystone)" msgid "Web Interface" msgstr "Web interface" msgid "Script returned exit code %s and output \"%s\"" msgstr "Notification script returned exit code %s and output \"%s\"" msgid "If empty, the standard port will only listen to HTTPS." msgstr "If empty, the SABnzbd Port set above will listen to HTTPS." msgid "Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay." msgstr "Posts will be paused until they are at least this age. Setting job priority to Force will skip the delay." msgid "Support the project, Donate!" msgstr "Support the project, donate!" msgid "User script can flag job as failed" msgstr "Post-processing script can flag job as failed" msgid "When the user script returns a non-zero exit code, the job will be flagged as failed." msgstr "When the post-processing script returns a non-zero exit code, the job will be flagged as failed." msgid "unrar binary... NOT found" msgstr "unrar binary... NOT found!" msgid "Downloads will not unpacked." msgstr "Downloads will not be unpacked." msgid "Seperate multiple URLs by a comma" msgstr "Separate multiple URLs with a comma" msgid "Advanced" msgstr "Advanced Settings" SABnzbd-2.3.2/po/main/es.po0000644000000000000000000045405213217005051013444 0ustar 00000000000000# Spanish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2017-06-22 07:07+0000\n" "Last-Translator: Safihre \n" "Language-Team: Spanish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:31+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Error al iniciar la interfaz web" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "" "No se puede encontrar la plantilla web: %s, intentando con la plantilla " "estandar" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "módulo _yenc... NO encontrado!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "par2 binario... NO encontrado!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" "Su versión UnRAR es %s, recomendamos la versión %s o superior.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "unrar binario... NO encontrado" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "unzip binario... NO encontrado!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "No se encontró el binario de 7za" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Tenga en cuenta que el nombre de equipo 0.0.0.0 necesitará una dirección " "IPv6 para el acceso externo" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "Los puertos de HTTP y de HTTPS no pueden ser iguales" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "HTTPS deshabilitado debido a la falta de archivos CERT y KEY" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Error al iniciar la interfaz web: " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "No se ha podido conectar con el servicio SABHelper" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s comenzó" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Advertencia" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Se ha producido un error" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "Cierre de SABnzbd terminado" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "El hostname no está definido." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "No se han configurado conexiones. Configure al menos una conexión." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Contraseña protejido por ******, favor reingresar" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Detalles de servidor invalidos" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "Tiempo agotado: Trate conectar en puerto diferente o encender SSL." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Tiempo agotado" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Dirección del servidor no válida." #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "El servidor se ha cerrado durante el login" #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "El servidor necesita usuario y contraseña." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "¡Conexión exitosa!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Autenticación fallida, compruebe el usuario o la contraseña." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "Demasiadas conexiones; pause las descargas o inténtelo de nuevo más tarde" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "No se pudo determinar el resultado de la conexión (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Señal %s capturado, guardando y saliendo..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Error grave al guardar estado" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Tratando de buscar NZB de %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Guardar de %s no se pudo completar." #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "No se puede crear el archivo temporal para %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Intentando cambiar el estado de servidor inexistente %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Fallo en tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Cargar de %s no se pudo completar." #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Falló la carga de %s con el error %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Notificación de prueba" #: sabnzbd/api.py msgid " Resolving address" msgstr " Resolviendo sitio" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Ninguno" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Predeterminado" #: sabnzbd/api.py msgid "unknown" msgstr "desconocido" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Compilación de regex para término fallo: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "Muy poco espacio en disco forzando PAUSA" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Disco lleno! Pausando la cola" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Error de disco al crear el archivo %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Error grave en el ensamblador" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Abortado, detectamos cifrados" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "ADVERTENCIA: Se ha encontrado una extensión no deseada en el fichero RAR " "\"%s\". El fichero no deseado es %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "Se ha encontrado una extensión desconocida en el fichero rar %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Se interrumpió la acción porque se detectó una extensión no deseada" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "" "ADVERTENCIA: Se ha pausado el trabajo \"%s\" debido a su puntuación (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "" "ADVERTENCIA: Se ha abortado el trabajo \"%s\" debido a su puntuación (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Abortado, se ha encontrado un filtro de calificación (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "Falta %s" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "vídeo" #: sabnzbd/assembler.py msgid "audio" msgstr "audio" #: sabnzbd/assembler.py msgid "spam" msgstr "correo basura" #: sabnzbd/assembler.py msgid "passworded" msgstr "protegidos por contraseña" #: sabnzbd/assembler.py msgid "downvoted" msgstr "votados negativamente" #: sabnzbd/assembler.py msgid "keywords" msgstr "palabras clave" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Quota gastado, pausando cola" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s no es una dirección de correo electrónico válida." #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Se necesita la dirección del servidor" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "No se puede crear %s la carpeta %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "No se puede escribir al archivo INI %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "No se puede crear copia de seguridad del archivo %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Contraseña incorrectamente codificado %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s no es un valor octal correcto" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "Ruta de acceso UNC \"%s\" no permitido aqui" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Error: La longitud de ruta debería ser menor que %s." #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Error: Cola no esta vacía, no se puede cambiar el directorio" #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "" "No se puede escribir en la base de datos de historia, compruebe los derechos " "de acceso !" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "" "La base de datos del Historial está dañada, se ha reemplazado vaciándola" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "Comando SQL ha fallado, vea el registro" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "No se pudo cerrar el base de datos, vea el registro" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Registro de etapa invalido para transferencia terminada %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Descodificación %s fallo" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Articulo yEnc corrupto en %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Error inespecifico mientras descodificando %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "UUencode detectada, la única codificación válida es Enc [%s]" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => faltando de todos servidores, desechando" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Completado" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "Descompresos %s archivos/directorios en %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "No se puede leer %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Error al añadir %s, eliminando" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Error al quitar %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Directorio Watched %s no se puede leer" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Reanudando" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "En pausa" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Debe establecer un ancho de banda máximo antes de poder establecer un límite " "de ancho de banda" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "El servidor %s se ignorará por %s minutos" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Error al inicializar %s@%s con la razón: %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "Demasiadas conexiones con el servidor %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Compartiendo de cuenta probable" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Registraccion fallo para servidor %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Error en inicio de conexion a servidor %s [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "Ha fallado la conexión a %s@%s, el mensaje=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "El servidor %s requiere usuario/contraseña" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Error sospechoso en downloader" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Apagando" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "No se pudo conectar al servidor de correo" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "No se pudo inicializar la conexión TLS" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "El servidor no respondió adecuadamente al saludo helo" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "No se pudo autenticar con el servidor de correo" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "No se ha encontrado ningún método de autenticación adecuado" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "" "Se produjo un fallo de autenticación desconocido en el servidor de correo" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "No se pudo enviar correo electrónico" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "No se pudo cerrar la conexión de correo" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "Email exitoso" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "No se ha podido enviar, faltan datos" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "No se pudo encontrar plantillas de email en %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Sin destinatarios no se pudo enviar el email" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Codificación de plantilla invalido %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "No se encontraron plantillas de correo electrónico" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "Para: %s\n" "De: %s\n" "Fecha: %s\n" "Asunto: SABnzbd informa de un disco lleno\n" "\n" "Hola:\n" "\n" "SABnzbd ha detenido las descargas porque casi se ha llenado el disco.\n" "Haga algo de espacio y reanude SABnzbd manualmente.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "Alerta: LOCALHOST es ambiguo, use dirección de IP numérica" #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "La dirección del servidor «%s:%s» no es válida." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "Usuario conectado a la interfaz web" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "Usuario conectado" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Falta clave de sesión" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Error: Clave de sesión requerido" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Error: Clave de sesión erróneo" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "Falta clave de API, favor ingresar la clave desde Config->General en tu " "aplicacion externa:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "Clave de API erróneo, favor ingresar la clave correcta desde Config->General " "en tu aplicacion externa:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Faltaron datos de cuenta, favor ingresar usuario/contraseña desde Config-" ">General en tu aplicacion externa:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "¡Prueba nuestra nueva skin Glitter! Un nuevo diseño recién salido del horno, " "optimizado para dispositivos de sobremesa y móviles. Ves a Configuración -> " "General para cambiar la skin." #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
Apago de SABnzbd exitoso.
Espere unos 5 segundos y entonces " "seleccione el boton abajo.

Refrescar
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Canal" #: sabnzbd/interface.py msgid "Daily" msgstr "Diariamente" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "Lunes" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Martes" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Miércoles" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Jueves" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Viernes" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Sábado" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Domingo" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "desactivado" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "¡Servidor no definido!" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Parámetro incorrecto" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Atrás" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "ERROR:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Valor incorrecto para %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "d" #: sabnzbd/misc.py msgid "h" msgstr "h" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "No se pudo crear el directorio %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "Directorio %s: Error al acceder a %s" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Error al crear (%s)" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Error al mover %s a %s" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Error al crear la llave SSL y el certificado" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "No se puede cambiar los permisos de %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Ejecutando script" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Se ha abortado el PostProcesamiento (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Script" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "" "El anidamiento de descompresiones ha resultado demasiado profundo [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Uniendo" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Secuencia incompleta de archivos a unir" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Error al unir el fichero %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Error \"%s\" al unir archivos" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Error \"%s\" al ejecutar file_join en %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] %s ficheros unidos." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Error al descomprimir, %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Error \"%s\" al descomprimir ficheros RAR" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Error \"%s\" al ejecutar rar_unpack sobre %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "¡Error al eliminar %s!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Intentado descomprimir rar con contraseña \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Error al descomprimir; El archivo está protegido por contraseña" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Descomprimiendo" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Descomprimir" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Error al descomprimir; Imposible encontrar %s" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "ERROR: Imposible encontrar \"%s\"" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Error de CRC al descomprimir" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "ERROR: Ha fallado la comprobación CRC sobre \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "" "Error al descomprimir; ¿Error de escritura, o tal vez el disco está lleno?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "ERROR: Error de escritura (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Aperture de archivo fallo, la via es muy larga" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "ERROR: via es muy larga (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Error al descomprimir, chequea el log" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "ERROR: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Archivo RAR inutilizable" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "Fichero RAR corrupto" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s archivos en %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Error \"%s\" al ejecutar unzip() sobre %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Tratando 7zip con la contraseña \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "7ZIP conjunto \"%s\" es incompleta, no puede desempaquetar" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "No se pudo descomprimir %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Chequeo Rápido" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Reparar" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Chequeo Rápido OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Iniciando reparación" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "" "La verificación PAR ha fallado en %s, ¡aunque el QuickCheck ha sido " "satisfactorio!" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "La reparación ha fallado, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Error %s al ejecutar par2_repair en el conjunto %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Error %s al ejecutar par2_repair en el conjunto %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] PAR2 ha recibido opciones incorrectas, chequea tus ajustes en " "Preferencias->Switches" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Verificado en %s, todos los archivos correctos" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Verificado en %s, se necesita reparar" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "Recuperando %s bloques..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Recuperando" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "" "Ha fallado la reparación, no existen bloques de reparación suficientes (%s " "short)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Reparando" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Reparado en %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Disco lleno" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Verificando" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Verificando" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Este servidor no permite SSL en este puerto" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Inicio/Apagado" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "NZB añadido" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Procesamiento posterior empezado" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Tarea finalizada" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Trabajo fallido" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Cola terminada" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Otros mensajes" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "No disponible" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "No se pudo enviar el mensaje de Prowl" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Mala respuesta de Pushover (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "No se pudo enviar el mensaje de Pushover" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Mala respuesta de Pushbullet (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "No se updo enviar el mensaje de Pushbullet" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "El script de notificación \"%s\" no existe" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "Fallo al mandar la notificación de Windows" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "" "Se ha encontrado una cola antigua, utilice Estado->Reparar para convertir la " "cola" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "" "Se ha encontrado un fichero de cola incompatible, no se puede continuar" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Error al cargar %s, archivo corrupto" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "Error al reiniciar NZB después de pre - chequeo (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB añadido a la cola" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Codificación desconocida" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "El fichero%s está vacío, omitiendo" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Error al importar %s ficheros desde %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Fichero NZB %s incompleto" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Fichero NBZ inválido: %s, omitiendo (razón=%s, línea=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Fichero NZB vacío: %s" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Ignorando NZB Duplicado \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Pausando NZB duplicados \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Abortado, No puede ser completado" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "DUPLICADO" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "ENCRIPTADO" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "DEMASIADO GRANDE" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "INCOMPLETO" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "NO DESEADO" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "FILTRADO" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "ESPERAR %s seg" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "PROPAGANDO %s min" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Descargado en %s a una media de %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Edad" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s artículos estaban mal formados." #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s artículos no encontrados" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s artículos contenían duplicados inconexos" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s articulos removidos" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Error importando %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Advertencias" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Inactivo" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Configuración" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Cola" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Limpiar Cola" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Historial" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Purgar historial" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Limitar Velocidad" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Pausar" #: sabnzbd/osxmenu.py msgid "min." msgstr "mín." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Reanudar" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Escanear directorio bajo observación" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Leer todos los canales RSS" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Carpeta Completa" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Carpeta Incompleta" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Resolver un problema" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Reiniciar" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Reiniciar sin sesión iniciada" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Salir" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Encolar los primeros 10 elementos" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Vacía" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Histórico últimos 10 elementos" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Nueva versión disponible" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Ir al Asistente" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Deteniendo..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Problema con" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd necesita un puerto tcp/ip libre para su servidor web " "interno.
\n" " Se ha intentado en el puerto %s en %s, pero no está disponible.
\n" " Puede que otro software ya esté utilizando este puerto, o que SABnzbd ya " "esté en ejecución.
\n" "
\n" " Por favor reinicia SABnzbd indicando un número de puerto diferente." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "" "Si obtiene este mensaje de error consecutivamente, por favor inténtelo de " "nuevo con otro número.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd necesita una dirección IP para su servidor web interno.
\n" " Has especificado una dirección inválida.
\n" " Valores seguros son localhost y 0.0.0.0
\n" "
\n" " Por favor reinicia SABnzbd con una dirección o nombre de host correctos." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd ha detectado información guardada de otra versión de " "SABnzbd
\n" " pero no puede ser reutilizada por la otra versión.

\n" " Tal vez quieras finalizar primero tu cola actual con la otra " "versión.

\n" " Tras ello, ejecuta este programa con la opción \"--clean\".
\n" " Esto eliminará la cola e historial actuales!.
\n" " SABnzbd leer el archivo \"%s\"" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd no puede encontrar sus ficheros de la interfaz web en %s.
\n" " Por favor instala el programa de nuevo.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd ha detectado un error grave:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd ha detectado que el fichero sqlite3.dll no existe.

\n" " Algunos virus de de pésima calidad eliminan este fichero.
\n" " Por favor revisa la configuración de tu antivirus y quéjate a tu " "proveedor del AntiVirus. Tras ello reinstala SABnzbd.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Presiona la Tecla de Windows+R y teclea la línea (ejemplo)" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Apre una ventana de Consola y teclea la línea (ejemplo)" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "El programa no ha arrancado!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Error grave" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "" "Imposible iniciar el navegador, probablemente no se le haya encontrado" #: sabnzbd/panic.py msgid "Access denied" msgstr "Acceso denegado" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Error %s: Necesitas introducir un usuario y contraseña válidos." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "La descarga fallo, solo %s de los %s requeridos estan disponibles" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Descarga fallida - No está en tu(s) servidor(es)" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "No se ha podido post-procesar debido a un fallo en la verificación" #: sabnzbd/postproc.py msgid "Moving" msgstr "Moviendo" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "Enviado(s) %s a la cola" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Error al renombrar \"%s\" a \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Error al mover ficheros" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Ejecutando script de usuario %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "Se ejecutó %s" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "El código de retorno del Script es %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Más" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Error al post-procesar %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "ver fichero de log" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "La descarga falló" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Ha fallado la limpieza de %s" #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Error al eliminar el directorio de trabajo (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Descarga Completada" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Imposible crear directorio final %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Post-Procesado" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] No hay conjuntos par2" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Intentando verificación por SFV" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Han fallado algunos ficheros al verificarse \"%s\"" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Se ha verificado correctamente utilizando ficheros SFV" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "Con contraseña" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Error al eliminar %s" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Error al hibernar el sistema" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Error al suspender el sistema" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Error al apagarel sistema" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "" "Identificación del indexador (%s) no encontrado para archivo de " "calificaciones" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Dirección del Servidor" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "Clave API" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "iaDescripción de canal RSS incorrecta \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Error al recuperar RSS desde %s: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "No se encontró autenticación válida para el feed %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "" "Error del lado servidor (código enviado por el servidor: %s); no se ha " "podido conseguir %s en %s" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "El servidor %s utiliza un certificado HTTPS no fiable" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "El canal RSS %s estaba vacío" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Canal Incorrecto" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Entrada RSS vacía (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Mostrar interfaz" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Abrir todo el folder" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Apagar" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Restante" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Añadir NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Planificación incorrecta %s a las %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Acción desconocida: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Planificación para servidor %s inexistente" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Descargar" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Unir ficheros" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Fuente" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Servidores" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Fallo" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Fallido" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "En espera" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Reparando..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Extrayendo..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Moviendo..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Ejecutando script..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Recuperando bloques extra..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Chequeo Rápido..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Verificando..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Descargando" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "Demora de la propagación" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Frecuencia" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Acción" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Argumentos" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Tarea" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "deshabilitar servidor" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "habilitar servidor" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Límite de Velocidad" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Pausar todo" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Pausar post-procesamiento" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Reanudar post-procesamiento" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Leer entradas RSS" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Eliminar trabajos fallidos" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Eliminar trabajos completados" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Pausar trabajos de prioridad baja" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Pausar trabajos de prioridad normal" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Pausar trabajos de prioridad alta" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Reanudar trabajos de prioridad baja" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Reanudar trabajos de prioridad normal" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Reanudar trabajos de prioridad alta" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Habilitar la administración de cuota" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Gestión de cuotas Desactivar" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Apagado" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Muy baja" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Moderada" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normal" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Alta" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Emergencia" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Baja" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "MB" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "GB" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "hora" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "horas" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "mín" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "mins" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "seg" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "segundos" #: sabnzbd/skintext.py msgid "day" msgstr "día" #: sabnzbd/skintext.py msgid "days" msgstr "días" #: sabnzbd/skintext.py msgid "week" msgstr "semana" #: sabnzbd/skintext.py msgid "Month" msgstr "Mes" #: sabnzbd/skintext.py msgid "Year" msgstr "Año" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Día del mes" #: sabnzbd/skintext.py msgid "This week" msgstr "Esta semana" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Este mes" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "Hoy" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Total" #: sabnzbd/skintext.py msgid "on" msgstr "activado" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parametros" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Version de Python" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Pagina principal" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "o" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Equipo" #: sabnzbd/skintext.py msgid "Comment" msgstr "Comentar" #: sabnzbd/skintext.py msgid "Send" msgstr "Enviar" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Cancelar" #: sabnzbd/skintext.py msgid "Other" msgstr "Otro" #: sabnzbd/skintext.py msgid "Report" msgstr "Denunciar" #: sabnzbd/skintext.py msgid "Video" msgstr "Vídeo" #: sabnzbd/skintext.py msgid "Audio" msgstr "Audio" #: sabnzbd/skintext.py msgid "Not used" msgstr "No usado" #: sabnzbd/skintext.py msgid "or less" msgstr "o menos" #: sabnzbd/skintext.py msgid "Log in" msgstr "Iniciar sesión" #: sabnzbd/skintext.py msgid "Log out" msgstr "Cerrar sesión" #: sabnzbd/skintext.py msgid "Remember me" msgstr "Mantenerme conectado" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "La herramienta de descarga automática para usenet" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Guardar" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "¿Estás seguro?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "¿Elimiar todos los ficheros descargados?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Inicio" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Config." #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Estado" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Ayuda" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Foro" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "Problemas" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "¡Apoye el proyecto, haga una donación!" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "General" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Directorios" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Switches" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Planificación" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Notificaciones" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "Correo" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Categorías" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Ordenación" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Especial" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Buscar" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Dir de Descarga" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "PAUSADO" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "%s artículos cacheados (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Carga del Sistema" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Nueva versión %s disponible en" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "¿Seguro que deseas detener SABnzbd?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Añadir" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Añadir fichero" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Categoría" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "En proceso" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Prioridad" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Reparar" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Descomprimir" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Eliminar" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "U" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "D" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Forzar" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Parar" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "Introduzca la URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "Al finalizar cola" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Apagar PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "Suspender PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Hibernar PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Apagar SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Límite de velocidad" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Pausar durante" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Orden" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Nombre" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "Tiempo estimado" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "ANTIGÜEDAD" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Borrar" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Reintentar" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Acciones" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Scripts" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "¿Eliminar todos los elementos de la cola?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Purgar NZBs" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Purgar NZBs y Eliminar Ficheros" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Vuelva a intentar todos los trabajos con errores" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Eliminar NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Eliminar NZB y Eliminar Ficheros" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "de" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Artículos no encontrados" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Quota disponible" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "manual" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Reinicializar Quota ahora" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "¿Eliminar todos los elementos completados del Historial?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Ocultar detalles" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Mostrar detalles" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Mostrar los Fallidos" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Mostrar Todo" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Tamaño" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Purgar los NZBs fallidos" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Purgar NZBs fallidos y sus ficheros" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Purgar NZBs completados" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "NZB Suplementario Opcional" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Ruta" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Re-intentar todos los fallados" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Re-intentar todo" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus / spam" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "Fuera de retención" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Otro problema" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Forzar desconexión" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Se enviará un email de prueba a tu cuenta" #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Ver Logging" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Email de prueba" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Registros de sucesos" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Errores/Advertencias" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+Info" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+Depuración" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Conexiones" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Últimas advertencias" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "limpiar" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Desbloquear" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Identificador de artículo" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Conjunto de ficheros" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Cuando" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Tipo" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Habilitado" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Tablero" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "¡Ha fallado la conexión!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Dirección IPv4 local" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Dirección IPv4 pública" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "Dirección IPv6" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Nombre del servidor / Búsqueda de DNS" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "Modelo de CPU" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "Rendimiento del sistema ( Pystone )" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "La velocidad de descarga carpeta" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Velocidad completa carpeta" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "velocidad de escritura" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "" "No se pudo escribir . Compruebe que el directorio tiene permisos de " "escritura ." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "" "Haga clic en el botón de prueba Repita a continuación para determinar" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Repita la prueba" #: sabnzbd/skintext.py msgid "Config File" msgstr "Fichero de Config" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Caché utilizada" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Esto reiniciará SABnzbd.
Usalo cuando creas que el programa está " "colgado.
Las descargas se pausarán antes de reiniciar, y se reanudarán " "a continuación." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "Si la autenticación esta activada, tendrás que conectarte de nuevo." #: sabnzbd/skintext.py msgid "Advanced" msgstr "" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Existen trabajos huérfanos en la carpeta de descarga.
Puedes escoger " "por eliminarlos (incluyendo los ficheros) o enviarlos de nuevo a la cola." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "El botón \"Reparar\" reiniciará SABnzbd y hará una reconstrucción
completa del contenido de la cola, preservando las descargas ya " "terminadas.
Esto modificará el orden de la cola." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "No se han guardado los cambios, y se perderán." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "Cuando tu dirección IP cambie o reinicies SABnzbd, la sesión caduca." #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Habilitar Unzip" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "Habilitar 7zip" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" #: sabnzbd/skintext.py msgid "Version" msgstr "Versión" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Tiempo en Activo" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Copia de seguridad" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Lee la ayuda en la Wiki (inglés) acerca de esto!" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Reiniciando SABnzbd..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Los cambios requieren reiniciar SABnzbd!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "Servidor web de SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "Host de SABnzbd" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Dónde debería escuchar el Host de SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "Puerto de SABnzbd" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Puerto en que SABnzbd debería escuchar" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Interfaz web" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Elije una piel" #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "Usuario SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Nombre de usuario opcional" #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "Contraseña de SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Contraseña opcional" #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "Habilitar HTTPS" #: sabnzbd/skintext.py msgid "not installed" msgstr "no instalado" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Habilia el acceso a la interfaz con una dirección HTTPS" #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "Puerto HTTPS" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Si se deja vacío, el puerto estándar escuchará por HTTPS" #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "Certificado HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Nombre de archivo o ruta al Certificado SSL" #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "Clave privada SSL" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Nombre de archivo o ruta a la clave privada SSL" #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "Cadena de Certificados HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Nombre de archivo o ruta de acceso a la cadena de HTTPS." #: sabnzbd/skintext.py msgid "Tuning" msgstr "Ajustes" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "Intervalo de chequeo RSS" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Intervalo de Chequeo (en minutos, mínimo 15). No toma efecto si utilizas el " "Planificador!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Velocidad máxima de línea" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Porcentaje de velocidad de línea" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "" "Porcentaje de la velocidad de la línea que SABnzbd debería utilizar, por " "ejemplo 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Límite de cacheo de artículos" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Cachear artículos en memoria para reducir el acceso a disco.
En " "bytes, opcionalmente seguido de K,M,G. Por ejemplo: \"64M\" o \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Lista de elementos a limpiar" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Lista de extensiones de archivo que se deben eliminar después de la descarga " "
Por ejemplo : . nfo o nfo, sfv < /b>" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Guardar cambios" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "Restaurar valores por defecto" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Reiniciar" #: sabnzbd/skintext.py msgid "Language" msgstr "Idioma" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Selecciona un idioma para la interfaz web." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" "¡Ayúdanos a traducir SABnzbd en tu idioma!
Traduce textos que aun no " "tienen ninguna traducción o mejora los que ya lo están traducidos aquí:" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "" "Esta clave le permitirá a programas de terceros acceso completo a SABnzbd." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "Clave NZB" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "Esta clave permitirá acceso a programas de terceros para añadir NZBs a " "SABnzbd." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Generar nueva clave" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "Código QR de la clave API" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Lista de rangos de red local" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Todas las direcciones de red locales comienzan con estos prefijos (a menudo " "\" 192.168.1 . \" )" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Acceso a internet externa" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" #: sabnzbd/skintext.py msgid "No access" msgstr "Acceso denegado" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Añadir archivos NZB " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (sin Config)" #: sabnzbd/skintext.py msgid "Full API" msgstr "API completa" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Interfaz web completa" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "Solo acceso externo requieren conexión de usuario" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "NOTA: Los directorios se crean automáticamente al guardar. Puedes " "usar una ruta absoluta, exterior a los directorios predefinidos." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Directorios del usuario" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Examinar" #: sabnzbd/skintext.py msgid "In" msgstr "En" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Directorio de descarga temporal" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Localización donde guardar descargas incompletas.
Sólo se puede " "cambiar si la cola est&aa; vací" #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Espacio libre mínimo para el directorio de descargas temporales" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Parar automáticamente cuando el espacio libre esté por debajo de este " "valor.
En bytes, opcionalmente seguido de K,M,G,T. Por ejemplo: " "\"800M\" ó \"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Directorio de descargas completadas" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Ubicación donde guardar descargas finalizadas, totalmente procesaddas.
Puede ser obviado debido a categorías definidas por el usuario." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Permisos para descargas completadas" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Ajustar patrón de permisos para ficheros/directorios completados.
En " "notación ocal. Por ejemplo:\"755\" ó \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Directorio a vigilar" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Directorio a monitorizar en busca de ficheros .nzb.
También escanea " "ficheros .zip .rar y .tar.gz en busca de ficheros .nzb." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Velocidad de escaneo de la carpeta vigilada" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Número de segundos entre pasadas en busca de ficheros .nzb." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Directorio de plantillas de Email" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "" "Directorio que contiene plantillas de email definidas por el usuario." #: sabnzbd/skintext.py msgid "Password file" msgstr "Archivo de contraseñas" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Fichero que contiene todas las contraseñas a usar en ficheros RAR protegidos." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Directorios del sistema" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Directorio de administración" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Ubicación de la base de datos de historial y administración.
Sólo se " "puede cambiar si la cola está vacía." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "Los datos no se moverán. Requiere queu SABnzbd sea reiniciado!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Directorio de Historial" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Ubicación de los ficheros de log para SABnzbd.
Requiere reiniciar " "SABnzbd!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr "Directorio de Backups de .nzbs" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Ubicación donde se guardarán los ficheros .nzb." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Directorio base por defecto" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Descargar todos los archivos PAR2" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Activar descompresión recursiva" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Descomprimir archivos (rar,zip,7z) dentro de otros archivos." #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Ignorar cualquier carpeta dentro de archivos" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Todos los archivos irán en una sola carpeta ." #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Sólo obtener artículos para el primer elemento de la Cola" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Habilitar para usar menos memoria. Deshabilitar para prevenir que trabajos " "que se ralentizen bloqueen la cola." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Post-procesar sólo trabajos verificados" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "" "Sólo realiza el post-procesado en trabajos que han pasado todos los chequeos " "PAR2." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Accion cuando un archivo RAR cifrado es bajado" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "In caso de PAUSA, necesitara escribir una contrasena para continuar el " "trabajo." #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Detectar descargas duplicadas" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Detectar episodios duplicadas en serie" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Descartar" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Abortar" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Acción al detectar extensiones no deseadas" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "Acción cuando se detecta una extensión no deseada en archivos RAR" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "extensiones no deseadas" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Enumerar todas las extensiones no deseadas . Por ejemplo : < b> exe < / b > " "o < b> exe, com < / b >" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Habilitar verificacion basada en SFV" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Realiza una verificación extra basada en ficheros SFV." #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Script de usuario puede marcar un trabajo como fallado" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Cuando la secuencia de comandos de usuario devuelve un código de salida " "distinto de cero, el trabajo se marca como fallido ." #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "En caso de fallo, intentar con un NZB alternativo" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "" "Algunos servidores ofrecen una NZB alternativa cuando falla una descarga ." #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Habilitar renombrado de directorios" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Usa nombres temporales durante el procesado. Deshabilitalo si tu sistema se " "vuelve inestable con ello habilitado." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Script de usuario Pre-cola" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Se usa precediendo a la entrada de un NZB en la cola del sistema." #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Parámetros PAR2 extra" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Parámetros Nice" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "Parámetros IONice" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Desconectar si la cola está vacía" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "" "Desconecta del servidor de Usenet cuando la cola está vacía, o pausada." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Ordenar por antigüedad" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Automáticamente ordenar elementos por antigüedad (promedio)." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" "Los mensajes serán pausados hasta que alcancen al menos esta edad. Esta " "espera puede evitarse si se le da el valor Forzar a la prioridad de la " "tarea." #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Buscar Nva Versión" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Chequear semanalmente por nuevas versiones de SABnzbd." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "También libera de prueba" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Reemplazar espacios en el nombre de directorio" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "" "Reemplaza los espacios con guiones bajos en los nombres de directorio." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Reemplazar puntos en los directorios" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Reemplaza los puntos con espacios en los nombres de directorio." #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Hacer compatible con Windows" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "" "Para los servidores : asegúrese de que los nombres son compatibles con " "Windows ." #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Lanzar navegador al Arrancar" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Ejecuta el navegador por defecto del sistema al arrancar SABnzbd." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Pausar Descargas Durante el Post-Procesado" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Pausa las descargas al principio del post-procesado, y reanuda al terminar." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Ignorar Samples" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Filtra la descarga de ficheros de ejemplo (e.g. un sample de vídeo)." #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Eliminar tras descargar" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "Validación del certificado HTTPS" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" "Verificar certificados al conectarse a indexadores y fuentes RSS usando " "HTTPS." #: sabnzbd/skintext.py msgid "Server" msgstr "Servidor" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Post procesado" #: sabnzbd/skintext.py msgid "Naming" msgstr "Nombrado" #: sabnzbd/skintext.py msgid "Quota" msgstr "Cuota" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indexación" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Cantidad de descarga permitida este mes (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Día de reinicio del conteo" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "En qué día del mes o semana (1=Lunes) resetea tu proveedor la cuota mensual? " "(Opcional con hh:mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Auto reanudar" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "¿Deberían las descargas resumirse tras reiniciarse la cuota?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Periodo de la cuota" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "¿Cada cuánto se resetea la cuota?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Chequear antes de descargar" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Intenta predecir si la descarga actual se completará con éxito (ojo, esto " "tarda!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Reintentos máximos" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Máximo número de reintentos por servidor" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Trabajos abortados no pueden ser completados" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Cuando este bajando, si es claro que mucha data esta faltando, aborte el " "trabajo." #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Habilitar Filtrado" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Acciones de descarga acordes a las reglas de filtrado." #: sabnzbd/skintext.py msgid "Abort If" msgstr "Abortar si" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "sino pausar si" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Puntuación" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Valoración de Audio" #: sabnzbd/skintext.py msgid "Spam" msgstr "Spam" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Confirmado" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Más votos negativos que positivos" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Palabras clave" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Lista separada por comas" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Balanceo de carga del servidor" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Evitar el balanceo de carga" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Permitir balanceo de carga" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Permitir balanceo de carga con optimización para IPv6" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "" "Útil si un servidor de noticias tiene más de una dirección IPv4 / IPv6" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Añadir servidor" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Descripción del servidor" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Puerto" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Nombre de usuario" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Contraseña" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Expiración del plazo (Timeout)" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Periodo de retención" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Deshabilitado" #: sabnzbd/skintext.py msgid "Minimal" msgstr "" #: sabnzbd/skintext.py msgid "Strict" msgstr "" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 El prioridad más alta, 100 es la prioridad más baja" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Opcional" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Habilitar" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Eliminar servidor" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Probar Servidor" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Resetear contadores" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Testeando información del servidor" #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Ancho de Banda" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Enviar Group" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Enviar comando group antes de solicitar los artículos." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Sólo utilizar este servidor para estas categorías ." #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" "Ninguno de los servidores activos tiene la categoría \"por defecto\" " "seleccionada. Las tareas en espera que no estén asignadas a una categoría " "del servidor no serán descargadas." #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Notas personales" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Añadir planificación" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Tareas Programadas Actuales" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "La casilla junto al nombre de la fuente debería marcarse para habilitar la " "fuente y que se marquen automáticamente los nuevos elementos.
Cuando " "una fuente se añade, sólo se cogerán los elementos nuevos y nada de lo que " "ya exista, salvo que presiones \"Forzar Descarga\"." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Leer Fuente" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Forzar Descarga" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Filtrar" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Aceptar" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Rechazar" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Necesita" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "RequiereCat" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Al menos" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Como máximo" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "De SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Encontrado(s)" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "No encontrado" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Descargado" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Leer todas las fuentes ahora" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "Notificación por email al terminar" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Nunca" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Siempre" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Sólo Errores" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Notificaciones de Disco Lleno" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "" "Envía un email cuando el disco se ha llenado y SABnzbd se ha tenido que " "parar." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Enviar notificaciones RSS" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "Enviar email cuando una fuente RSS añade un trabajo a la cola." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "Servidor SMTP" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Indica los ajustes de tu correo electrónico saliente." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "Destinatario" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "Dirección de correo electrónico a la que enviar el mensaje." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "Remitente" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "¿Quién quieres que aparezca como remitente?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "Nombre de usuario OPCIONAL" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "" "Para correos electrónicos con autentificación, poner el nombre de usuario." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "Contraseña de usuario OPCIONAL" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Para correos electrónicos con autentificación, poner la contraseña." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Habilitar Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Enviar notificaciones a Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Usar sólo para un servidor Growl remoto (servidor:puerto)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Contraseña de servidor" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Contraseña opcional para el servidor Growl" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "Habilitar NotifyOSD" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Enviar notificaciones a NotifyOSD" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Centro de Notificación" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Envía notificaciones al Centro de Notificación" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Activar notificaciones Windows" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Notificaciones Windows" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Activar notificaciones Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Necesitas una cuenta Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "Clave API de Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Clave privada de la API de Prowl" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Activar notificaciones Pushover" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Necesitas una cuenta Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Token de aplicación" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Token de aplicación (obligatorio)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Clave de usuario" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Clave de usuario (obligatoria)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Dispositivo(s)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Dispositivo(s) a los que enviar el mensaje" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Activar notificaciones Pushbullet" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Necesitas una cuenta en Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Clave API personal" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Tu clave API personal de Pushbullet (obligatoria)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Dispositivo" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Dispositivo al que enviar el mensaje" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "Script de notificación" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "Activar script de notificación" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "Ejecutar un script personalizado" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "¿Que script deberíamos ejecutar para notificaciones?" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Terminar la ruta con un * previene que se creen directorios de trabajo." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Los directorios relativos, lo son a" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Directorio/Ruta" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Ordenación de Series" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Habilitar la ordenación de Series de TV" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Patrón" #: sabnzbd/skintext.py msgid "Clear" msgstr "Limpiar" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "" #: sabnzbd/skintext.py msgid "Presets" msgstr "Preajustes" #: sabnzbd/skintext.py msgid "Example" msgstr "Ejemplo" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Habilitar Ordenado de Películas" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Mantener descargas en directorios extra." #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Categorías Afectadas" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Significado" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Patrón" #: sabnzbd/skintext.py msgid "Result" msgstr "Resultado" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Temporada Directorio" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Temporada Directorio" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Episodio Directorio" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Episodio Directorio" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Título" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Nombre de Película" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Nombre.de.pelicula" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Nombre_de_pelicula" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Nombre de la Serie" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Nombre.serie" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Nombre_serie" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Número de la temporada" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Número del capítulo" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Nombre del capítulo" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Nombre.capítulo" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Nombre_capítulo" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Extensión de archivo" #: sabnzbd/skintext.py msgid "Extension" msgstr "Extensión" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Numero de Parte" #: sabnzbd/skintext.py msgid "Decade" msgstr "Década" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Nombre fichero original" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Minúsculas" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEXTO" #: sabnzbd/skintext.py msgid "text" msgstr "texto" #: sabnzbd/skintext.py msgid "file" msgstr "archivo" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Ordenar cadena" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Etiqueta" #: sabnzbd/skintext.py msgid "In folders" msgstr "En directorios" #: sabnzbd/skintext.py msgid "No folders" msgstr "Sin Directorios" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Ordenar por fecha" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Habilitar ordenar por fecha" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Carpeta de la serie" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "Directorios Año-Mes" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Directorios diarios" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "ajustado a mayus-minus" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Resultado del procesado" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Opciones usadas raramente. Para su significado y explicación, haga clic en " "el botón de Ayuda para ir al Wiki.
No cambie esto sin chequear primero en " "la wiki,ya que algunos ajustes tienen severas consecuencias.
Los valores " "por defecto se muestran entre paréntesis." #: sabnzbd/skintext.py msgid "Values" msgstr "Valores" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Editar Detalles de NZB" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Eliminar" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Superior" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Encima" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Abajo" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Último" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Todos" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Invertir" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Nombre de archivo" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Asunto" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Selección" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Pausar 5 minutos" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Pausar 15 minutos" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Pausar 30 minutos" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Pausar 1 hora" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Pausar 3 horas" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Pausar 6 horas" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "Restante" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Espacio libre" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Carpeta temporal" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Op.Múltiples" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Mantén presionada la tecla shift para seleccionar un rango" #: sabnzbd/skintext.py msgid "Check all" msgstr "Marcar todo" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Reiniciar SABnzbd" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Opciones de estado e interfaz" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "¡ó arrastra y suelta ficheros en la propia ventana!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Se ha perdido la conexión con SABnzbd.." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "" "Esta ventana desaparecerá automáticamente una vez SABnzbd se haya reiniciado." #: sabnzbd/skintext.py msgid "WARNING:" msgstr "AVISO:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Obtener" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Frecuencia de actualización" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Usar ajustes de la interfaz global" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Límite de elementos encolables" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Límite del historial" #: sabnzbd/skintext.py msgid "Date format" msgstr "Formato de fecha" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Columna de cola extra" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "Columna de historia adicional" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "página" #: sabnzbd/skintext.py msgid "Loading" msgstr "Cargando" #: sabnzbd/skintext.py msgid "articles" msgstr "artículos" #: sabnzbd/skintext.py msgid "Rename" msgstr "Renombrar" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Reparar cola" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Mostrar conexiones activas" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Trabajos descolgados" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Enviar de nuevo a la cola" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Eliminar todo" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Re-intentar todo" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Descargar NZB desde URL" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "Subir NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Opcionalmente especificar un nombre de fichero" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Formatos: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Enviar" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Abrir URL de informacion" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Enviado. ¡Muchas gracias!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "¡No hay nada seleccionado!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Eliminar todos los ficheros seleccionados" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Ocultar/Mostrar ficheros completados" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Ver bitacora de Scripts" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "¡Actualización Disponible!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" "Tu buscador de internet tiene las cookies desactivadas, la configuración de " "la interfaz se perderá si cierras el explorador." #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "¡Glitter tiene alguna nueva funcionalidad que puede gustarte!" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Personalizar" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "Diseño compacto" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "Diseño de pestañas
(separa la cola de espera y la historia)" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Velocidad" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Confirmar eliminación de la cola" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Confirmar eliminación del historial" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "¿Durante cuánto tiempo quieres dejarlo pausado?" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "" "Lo siento, no hemos podido interpretar eso. Vuelve a intentarlo de nuevo." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Pausar durante..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Actualizar" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Ordenar por Fecha Más viejo→Más nuevo" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Ordenar por Fecha Más nuevo→Más viejo" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Ordenar por nombre A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Ordenar por nombre Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Ordenar por Tamaño Más pequeño→Más grande" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Ordenar por Tamaño Más grande→Más pequeño" #: sabnzbd/skintext.py msgid "Uploading" msgstr "Subiendo" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "Forzar la desconexión" #: sabnzbd/skintext.py msgid "Removing job" msgstr "Eliminar tarea" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "Eliminar tareas" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Anterior" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Siguiente" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "¿Vaciar el historial?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Debes activar JavaScript para que pueda funcionar Plush!" #: sabnzbd/skintext.py msgid "Options" msgstr "Opciones" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "¿Por cuántos minutos realizar la pausa?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Menú superior" #: sabnzbd/skintext.py msgid "On Finish" msgstr "Al terminar" #: sabnzbd/skintext.py msgid "Sort" msgstr "Ordenar" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Ordenar por Fecha (Más viejo→Más nuevo)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Ordenar por Fecha (Más nuevo→Más viejo)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Ordenar por nombre (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Ordenar por nombre (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Ordenar por Tamaño (Más pequeño→Más grande)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Ordenar por Tamaño (Más grande→Más pequeño)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "¿Limpiar la Cola?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "¿Re-intentar todos los trabajos con errores del Historial?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Purgar" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Velocidad máx." #: sabnzbd/skintext.py msgid "Range" msgstr "Intervalo" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Aplicar a seleccionados" #: sabnzbd/skintext.py msgid "Everything" msgstr "Todo" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Frecuencia de actualización" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Ancho del contenedor" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "" "Esto evitará que se actualizen los contenidos cuando el cursor del ratón " "esté sobre la cola." #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Bloquear actualizaciones al pasar por encima" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Subir" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Subir: .nzb .rar .zip .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Progreso" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "¡No hay espacio suficiente para completar las descargas!" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Libre (Temp)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "INACTIVO" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Descargas" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Eliminar completados" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "¿eliminar los elementos fallidos del historial?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Eliminar Fallidos" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "¿Re-intentar todos los trabajos con errores?" #: sabnzbd/skintext.py msgid "Links" msgstr "Enlaces" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Mostrando %s a %sde %s resultados" #: sabnzbd/skintext.py msgid "No results" msgstr "Sin resultados" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Mostrando un resultado" #: sabnzbd/skintext.py msgid "First" msgstr "Primero" #: sabnzbd/skintext.py msgid "Last" msgstr "Último" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "¡Email enviado!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "¡Notificación enviada!" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Guardando..." #: sabnzbd/skintext.py msgid "Saved" msgstr "Guardado" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Activar-desactivar Añadir NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "Vista Dual 1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "Vista Dual 2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "¿Seguro que desea reiniciar SABnzbd?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Ocultar opciones de edición" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Mostrar opciones de edición" #: sabnzbd/skintext.py msgid "Edit" msgstr "Modificar" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "TiempoRestante" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "Asistente de Configuración de SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "Versión de SABnzbd" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Anterior" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Detalles del servidor" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Por favor introduce los datos de tu proveedor principal de Usenet." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Número de conexiones permitidas a tu proveedor" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "P.ej. 8 ó 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Selecciona sólo si tu proveedor permite conexiones SSL." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Haz clic para probar los detalles introducidos." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Por ej." #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "¡La configuración ha terminado!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd ahora quedará ejecutando en segundo plano." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "Si cierras las pestañas o el navegador, SABnzbd NO se cerrará." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Se recomienda que guardes esta ubicación como favorito y la añadas a tu " "navegador para acceder a SABnzbd cuando quieras." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Puedes encontrar más ayuda en nuestro" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Ir a SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Salir SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Iniciar Asistente" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd se entrega SIN NINGUNA GARANTÍA.\n" "Este es un software libre, y eres bienvenido a redistribuirlo bajo " "determinadas condiciones.\n" "Está licenciado bajo la versión 2 ó posterior de GNU GENERAL PUBLIC " "LICENSE.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "Para poder descargar de Usenet, necesitas acceso con un proveedor. Tu " "proveedor de acceso a internet te lo puede dar, aunque recomendamos " "proveedores premium." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "¿No tienes proveedor de Usenet? Nosotros recomendamos probar %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Error al recuperar info de la serie (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Error al renombrar: %s a %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Error al renombrar ficheros similares: %s a %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "No se puede resolver el nombre de servidor" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Acceso no autorizado" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "El fichero no se encuentra en el servidor" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "EL URLGRABBER HA FALLADO" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Archivo NZB inusable" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "Error al recuperar la URL; %s" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "La carpeta «%s» no existe" #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Su versión de UNRAR no está recomendada, obténgalo desde " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgid "Downloaded so far" #~ msgstr "Descargado hasta ahora" #~ msgid "Try again" #~ msgstr "Inténtelo de nuevo" #~ msgid "SQL Commit Failed, see log" #~ msgstr "Compromiso SQL ha fallado, vea el registro" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "NOTICIA: Transferencia \"%s\" pausado por archivo cifrado" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "Error CRC en %s (%s -> %s)" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "" #~ "Programa Unrar no encontrado, descomprimir de archivos RAR no posible
" #~ msgid "Initiating restart...
" #~ msgstr "Reiniciando...
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "Programa Par2 no encontrado, reparacion no posible
" #~ msgid "Error: No secondary interface defined." #~ msgstr "Error: Interfaz secundario no iniciado" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "Tareas marcadas con un '*' no serán descargadas automaticamente." #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "La tarea \"%s\" ha sido re-agregada a la cola" #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "No se puede abrir la llave de registro \"%s\"." #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Falla al leer las llaves de registro para los directorios especiales" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "Falta el módulo pyopensll, favor de instalarlo para acceso https" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "" #~ "Imposible conectar a la clave HKEY_CURRENT_USER del registro de Windows" #~ msgid "Not matched" #~ msgstr "No encontrado(s)" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Error al descomprimir, faltan este(os) archivo(s):" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "" #~ "Error al descomprimir; se esperaba un archivo que no se ha podido " #~ "descomprimir" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Falta el siguiente archivo: %s => ¿Error al descomprimir?" #~ msgid "Main packet not found..." #~ msgstr "Paquete principal no encontrado..." #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Ficheros par2 inválidos, no se puede verificar o reparar" #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Error al importar módulo OpenSSL. Conectando sin SSL" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABNZBD no es compatible con algunos cortafuegos.
\n" #~ " %s
\n" #~ " Lo sentimos, pero no se puede resolver esta incompatibilidad en este " #~ "momento.
\n" #~ " Por favor contacta con el proveedor de tu cortafuegos.
\n" #~ "
\n" #~ msgid "OK" #~ msgstr "Aceptar" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd necesita un puerto tcp/ip libre para su servidor web " #~ "interno.
\n" #~ " Se ha intentado con el puerto %s en %s, pero la cuenta utilizada por " #~ "SABnzbd no tiene permisos para usarlo.
\n" #~ " En equipos OSX y Linux, los usuarios normales han de usar puertos por " #~ "encima de 1023.
\n" #~ "
\n" #~ " Por favor reinicie SABnzbd con un número de puerto diferente." #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Parece que estás usando ZoneAlarm con Windows Vista.
" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Error al eliminar nzo desde la cola de postprocesado (id)" #~ msgid "You have no permisson to use port %s" #~ msgstr "No tienes permisos para usar el puerto %s" #~ msgid "View script output" #~ msgstr "Ver salida del script" #~ msgid "Get NZB" #~ msgstr "Obtener NZB" #~ msgid "KB/s" #~ msgstr "KB/s" #~ msgid "Queued" #~ msgstr "En cola" #~ msgid "Complete Dir" #~ msgstr "Dir para completados" #~ msgid "Download speed" #~ msgstr "Velocidad de Descarga" #~ msgid "Add new downloads" #~ msgstr "Añadir nuevas descargas" #~ msgid "WARNINGS" #~ msgstr "AVISOS" #~ msgid " " #~ msgstr " " #~ msgid "Sort by name" #~ msgstr "Ordenar por nombre" #~ msgid "Sort by age" #~ msgstr "Ordenar por antigüedad" #~ msgid "Sort by size" #~ msgstr "Ordenar por tamaño" #~ msgid "Hide files" #~ msgstr "Ocultar Ficheros" #~ msgid "Show files" #~ msgstr "Mostrar archivos" #~ msgid "Remain/Total" #~ msgstr "Restante/Total" #~ msgid "Purge Failed History" #~ msgstr "Purgar historial de errores" #~ msgid "History Size" #~ msgstr "Tamaño del Historial" #~ msgid "Delete all failed items from History?" #~ msgstr "¿Eliminar todos los elementos que han fallado del Historial?" #~ msgid "Show Weblogging" #~ msgstr "Mostrar Logging de la web" #~ msgid "Thread" #~ msgstr "Hilo" #~ msgid "Email Test Result" #~ msgstr "Resultado del email de prueba" #~ msgid "General configuration" #~ msgstr "Configuración general" #~ msgid "Secondary Web Interface" #~ msgstr "Interfaz web secundaria" #~ msgid "HTTPS Support" #~ msgstr "Soporte HTTPS" #~ msgid "Activate an alternative skin." #~ msgstr "Habilitar una piel alternativa" #~ msgid "Web server authentication" #~ msgstr "Identificación contra el Servidor Web" #~ msgid "Queue auto refresh interval:" #~ msgstr "Intervalo automático de refresco de la cola" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "" #~ "Intervalo de refresco de la página web de la cola (en segundos, 0= ninguno)" #~ msgid "Do not require the API key." #~ msgstr "No solicitar clave API." #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "USALO BAJO TU RESPONSABILIDAD" #~ msgid "Disable API-key" #~ msgstr "Desactivar Clave-API" #~ msgid "QR Code" #~ msgstr "Codigo QR" #~ msgid "Folder configuration" #~ msgstr "Configuración Directorios" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Directorio de Scripts de post-procesado" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "" #~ "Directorio que contiene los scripts de usuario para el post-procesado." #~ msgid "Other Switches" #~ msgstr "Otros parámetros" #~ msgid "Server configuration" #~ msgstr "Configuración del servidor" #~ msgid "Remove" #~ msgstr "Eliminar" #~ msgid "Add Feed" #~ msgstr "Añadir una fuente" #~ msgid "Skip" #~ msgstr "Omitir" #~ msgid "RSS Configuration" #~ msgstr "Configuración de RSS" #~ msgid "Delete Feed" #~ msgstr "Borrar fuente" #~ msgid "Feeds" #~ msgstr "Fuentes" #~ msgid "Filters" #~ msgstr "Filtros" #~ msgid "Settings" #~ msgstr "Preferencias" #~ msgid "Email Options" #~ msgstr "Opciones de e-mail" #~ msgid "folder" #~ msgstr "carpeta" #~ msgid "Are you sure you want to delete" #~ msgstr "¿Está seguro de querer borrar?" #~ msgid "Page" #~ msgstr "Página" #~ msgid "Close" #~ msgstr "Cerrar" #~ msgid "Storage" #~ msgstr "Almacenamiento" #~ msgid "Access" #~ msgstr "Acceso" #~ msgid "Misc" #~ msgstr "Miscelánea" #~ msgid "This field is required." #~ msgstr "Este campo es obligatorio" #~ msgid " or Report ID" #~ msgstr "  ó ID de Reporte" #~ msgid "Switches configuration" #~ msgstr "Configuración de Switches" #~ msgid "Processing Switches" #~ msgstr "Procesando Switches" #~ msgid "Enable Quick Check" #~ msgstr "Habilitar Chequeo Rápido" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Ignorar chequeo de par2 cuando los ficheros son 100% correctos." #~ msgid "Enable Unrar" #~ msgstr "Habilitar Unrar" #~ msgid "Enable built-in unrar functionality." #~ msgstr "Habilitar funcionalidad nativa de unrar" #~ msgid "Enable built-in unzip functionality." #~ msgstr "Habilitar funcionalidad nativa de unzip." #~ msgid "Enable Filejoin" #~ msgstr "Habilitar Filejoin" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "Une los ficheros terminados en .001, .002 etc en un sólo fichero." #~ msgid "Enable TS Joining" #~ msgstr "Habilitar Unión TS" #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "" #~ "Une los ficheros terminados en .001.ts, .002.ts etc en un sólo fichero." #~ msgid "Enable Par Cleanup" #~ msgstr "Habilitar limpieza Par" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Limpiar ficheros par (si la reparación/verificación es correcta)." #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Fallar si hay errores de CRC en yEnc" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "" #~ "Cuando un artículo tiene un error de CRC, intentar conseguirle desde otro " #~ "servidor." #~ msgid "Check result of unpacking" #~ msgstr "Chequear el resultado de la descompresión" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Chequea el resultado de la descompresión (necesita deshabilitarse si tienes " #~ "un sistema de ficheros muy grande)." #~ msgid "Default Post-Processing" #~ msgstr "Post-Procesado por defecto" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "" #~ "Este es el post-procesado a utilizar cuando no se ha definido nada especial " #~ "según la categoría de la descarga." #~ msgid "Default User Script" #~ msgstr "Script de Usuario predefinido" #~ msgid "Used when no user script is defined by the category." #~ msgstr "Usado cuando la categoría no imponte ningún script de usuario." #~ msgid "Default Priority" #~ msgstr "Prioridad Predefinida" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Se usa cuando la categoría no impone ninguna prioridad." #~ msgid "Enable MultiCore Par2" #~ msgstr "Habilitar Par2 Multi-núcleo" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Reemplazar caracteres no admitidos en los directorios" #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Reemplaza los caracteres inválidos del nombre del directorio por lso " #~ "equivalentes (si no puede los elimina)." #~ msgid "Do not download" #~ msgstr "No descargar" #~ msgid "SSL type" #~ msgstr "Tpo de SSL" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "¡sa V23 salvo que tu proveedor indique lo contrario!" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Usar reloj de 12 horas (AM/PM)" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Muestra las horas en notación AM/PM (no afecta al planificador)." #~ msgid "Only for optional servers" #~ msgstr "Sólo para servidores opcionales/alternativos" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Aplica un máximo de reintentos a los servidores opcionales" #~ msgid "Server definition" #~ msgstr "Definición de Servidor" #~ msgid "Backup server" #~ msgstr "Servidor de Backup" #~ msgid "Click below to test." #~ msgstr "Haga clic debajo para testear." #~ msgid "Scheduling configuration" #~ msgstr "Config. de Planificación" #~ msgid "New Feed URL" #~ msgstr "URL de la fuente RSS" #~ msgid "Email Account Settings" #~ msgstr "Ajustes de E-Mail" #~ msgid "User-defined categories" #~ msgstr "Categorías definidas por el usuario" #~ msgid "Defines post-processing and storage." #~ msgstr "Define tareas de post-procesado y el almacenamiento." #~ msgid "Groups / Indexer tags" #~ msgstr "Grupos / Etiquetas del indizador" #~ msgid "Sorting configuration" #~ msgstr "Preferencias de ordenación" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Habilitar ordenación y renombrado de episodios." #~ msgid "Generic Sorting" #~ msgstr "Ordenado Genérico" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Habilitar ordenado y renombrado genérico de los ficheros." #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Habilitar si las descargas no quedan en sus propios directorios." #~ msgid "Original Foldername" #~ msgstr "Nombre directorio original" #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Habilitar ordenación y renombrado de nombres de ficheros con fechas." #~ msgid "Set Pause Interval" #~ msgstr "Ajustar Intervalo de Parada" #~ msgid "Pause Interval" #~ msgstr "Intervalo de Parada" #~ msgid "Pause for 12 hours" #~ msgstr "Pausar 12 horas" #~ msgid "Pause for 24 hours" #~ msgstr "Pausar 24 horas" #~ msgid "Plush Options" #~ msgstr "Opciones de Plush" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Subir: .nzb .rar .zip .gz" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Leer Fuente recogerá los contenidos actuales de la fuente. " #~ "Forzar Descarga para descargar ahora cualquier NZB " #~ "coincidente." #~ msgid "Hour:Min" #~ msgstr "Hora:Minuto" #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "Quiero que SABnzbd sea visible para cualquier ordenador en mi red." #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Quiero que SABnzbd sólo sea visible desde este ordenador." #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Proteger el acceso a SABnzbd con contraseña (recomendado)" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Habilitar HTTPS para acceder a SABnzbd." #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "" #~ "Lanzar mi navegador de interner con la página de SABnzbd al arrancar el " #~ "programa." #~ msgid "Please enter a whole number." #~ msgstr "Por favor introduzca un número completo." #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "Después de que se reinicie SABnzbd, podrás acceder a él en la siguiente " #~ "dirección: %s" #~ msgid "Step One" #~ msgstr "Primer Paso" #~ msgid "Step Two" #~ msgstr "Segundo Paso" #~ msgid "Step Three" #~ msgstr "Tercer Paso" #~ msgid "Step Four" #~ msgstr "Cuarto Paso" #~ msgid "Step Five" #~ msgstr "Quinto Paso" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "P.ej. 119 ó 563 si es SSL" #~ msgid "Open Source URL" #~ msgstr "Abrir URL Fuente" #~ msgid "Left" #~ msgstr "Restante" #~ msgid "Notification classes" #~ msgstr "Clases de notificación" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "" #~ "Activar clases de mensajes que deben notificarse (ninguno, uno o múltiples)" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "AVISO: Abortadeo el trabajo \"%s\" por un archivo RAR cifrado" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "" #~ "Enviar resultados de la validación calculados automáticamente descargas " #~ "hasta indexador ." #~ msgid "Automatic Feedback" #~ msgstr "Regeneración automática" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Esta clave proporciona identidad al indexador . Consulte " #~ "https://www.oznzb.com/profile ." #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Funcionalidad mejorada incluyendo calificaciones e información de estado " #~ "adicional está disponible cuando se conecta a OZnzb indexador ." #~ msgid "Enable OZnzb Integration" #~ msgstr "Habilitar Integración OZnzb" #~ msgid "Site API Key" #~ msgstr "Clave API del sitio" SABnzbd-2.3.2/po/main/fi.po0000644000000000000000000045706013217005051013435 0ustar 00000000000000# Finnish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2017-06-22 07:07+0000\n" "Last-Translator: Safihre \n" "Language-Team: Finnish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:30+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Web-käyttöliittymän käynnistys epäonnistui" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "Web-mallia %s ei löydy, yritetään käyttää oletusmallia" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "_yenc moduulia... EI löydy!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "par2 ohjelmaa... EI löydy!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" "UNRAR versiosi on %s, suosittelemme käyttämään versiota %s tai uudempaa.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "unrar ohjelmaa... EI löydy!" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "unzip ohjelmaa... EI löydy!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "7za ohjelmaa... EI löydy!" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Huomioithan, että 0.0.0.0 isäntänimi vaatii IPv6 osoitteen jotta pääset " "ulkoverkkoon" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "HTTP- ja HTTPS-portit eivät voi olla samoja" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" "SABnzbd käynnistettiin %s merkistökoodauksella. Tämän pitäisi olla UTF-8. " "Unicode-merkkejä tiedosto- ja kansionimissä sisältävät lataukset voivat " "aiheuttaa ongelmia." #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "HTTPS poistettu käytöstä puuttuvien CERT ja KEY tiedostojen vuoksi" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Web-käyttöliittymän käynnistys epäonnistui : " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "SABHelper palvelua ei voitu tavoittaa" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s käynnistetty" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Varoitus" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Virhe" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "SABnzbd sammutus valmis" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Isäntänimeä ei ole asetettu." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "Yhteyksiä ei ole asetettu. Aktivoi ainakin yksi yhteys." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Salasana on piilotettu ******, syötä uudelleen" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Virheelliset palvelimen tiedot" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "" "Aikakatkaistu: Yritä laittaa SSL päälle tai yhdistä toiseen porttiin." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Aikakatkaistiin" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" "Tuntematon SSL protokolla: Kokeile ottaa SSL käytöstä tai vaihda porttia." #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Virheellinen palvelimen osoite." #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Palvelin lopetettiin kesken kirjautumisen" #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Palvelin vaatii käyttäjänimen ja salasanan." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Yhdistäminen onnistui!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Varmennus epäonnistui, tarkista käyttäjänimi/salasana." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "Liikaa yhteyksiä, keskeytä lataaminen tai yritä myöhemmin uudelleen" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Yhteystestin lopputulosta ei voitu määrittää (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Signaali %s kaapattu, tallennetaan ja lopetetaan..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Vakava virhe tallennettaessa tilaa" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Yritetään noutaa NZB osoitteesta %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Kohteen %s tallentaminen epäonnistui" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Väliaikaistiedostoa ei voida luoda kohteelle %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Yritettiin asettaa tila ei olemassa olevalle palvelimelle %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Virhe tiedostossa tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Kohteen %s lataaminen epäonnistui" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Kohteen %s lataus epäonnistui virheeseen %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Testaa ilmoitusta" #: sabnzbd/api.py msgid " Resolving address" msgstr " Selvitetään osoitetta" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Ei mitään" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Oletus" #: sabnzbd/api.py msgid "unknown" msgstr "tuntematon" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Regex käännös epäonnistui hakutermille: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "Levytilaa ei ole tarpeeksi, pakotetaan KESKEYTYS" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Levy täynnä! Pakotetaan keskeytys" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Levyvirhe luotaessa tiedostoa %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Vakava virhe kohteessa Assembler" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Peruutettu, salattu arkisto tunnistettu" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "Varoitus: Latauksessa \"%s\" ei toivottu tiedostopääte RAR arkistossa. Ei " "toivottu tiedosto on %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "Ei toivottu tiedostopääte on rar arkistossa %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Peruutettu, ei toivottu tiedostopääte havaittu" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "VAROITUS : Keskeytetty lataus \"%s\", koska luokituksena (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "VAROITUS : Peruutettiin lataus \"%s\", koska luokituksena on (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Peruutettu, luokituksessa esiintyi suodatinosuma (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s puuttuu" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "video" #: sabnzbd/assembler.py msgid "audio" msgstr "ääni" #: sabnzbd/assembler.py msgid "spam" msgstr "roskaposti" #: sabnzbd/assembler.py msgid "passworded" msgstr "salasanasuojattu" #: sabnzbd/assembler.py msgid "downvoted" msgstr "epäsuosittu" #: sabnzbd/assembler.py msgid "keywords" msgstr "avainsanat" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Latausrajoitus saavutettu, keskeytetään lataukset" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s ei ole kelvollinen sähköpostiosoite" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Palvelimen osoite vaaditaan" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Ei voitu luoda %s kansiota %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Ei voitu kirjoittaa INI tiedostoa %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Ei voitu luoda varmuuskopiotiedostoa kohteelle %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Virheellisesti koodattu salasana %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s ei ole oikea oktaalinen arvo" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "TUNT polku \"%s\" ei ole sallittu" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Virhe: Polun pituus täytyy olla alle %s." #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Virhe: Jono ei ole tyhjä, kansiota ei voida vaihtaa." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "Historian tietokantaan ei voida kirjoittaa, tarkista käyttöoikeudet!" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "" "Historian tietokanta on vahingoittunut, luotiin uusi tyhjä tietokanta" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "SQL komento epäonnistui, katso loki" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Tietokannan sulkeminen epäonnistui, katso loki" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Virheellinen tila lokihistoriassa kohteelle %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Kohteen %s dekoodaus epäonnistui" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Huonosti muotoiltu yEnc artikkeli %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Tuntematon virhe dekoodattaessa %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "UUencode-koodaus havaittiin, vain yEnc-koodausta tuetaan [%s]" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => puuttuu kaikilta palvelimilta, hylätään" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Valmistunut" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "Purettiin %s tiedostoa/kansiota kohteeseen %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "Ei voida lukea %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Virhe lisättäessä %s, poistetaan" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Virhe poistettaessa %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Vahdittua kansiota %s ei voida lukea" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Jatketaan" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Keskeytetty" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Sinun täytyy määrittää enimmäiskaista ennen kaistarajoituksen käyttöönottoa." #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Palvelin %s ohitetaan %s minuutiksi" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Alustaminen epäonnistui kohteessa %s@%s syy: %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "Liikaa yhteyksiä palvelimelle %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Mahdollinen tilin jakaminen" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Kirjautuminen palvelimelle %s epäonnistui" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Palvelimeen %s ei voida yhdistää [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "Yhdistäminen %s@%s epäonnistui, viesti=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Palvelin %s vaatii käyttäjänimen/salasanan" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Mahdollinen virhe lataajassa" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Sammutetaan" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Postipalvelimeen yhdistäminen epäonnistui" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "TLS yhteyden aloittaminen epäonnistui" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "Palvelin ei vastannut oikein hello-pyyntöön." #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Postipalvelimen varmennus epäonnistui" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Yhteensopivan varmennustavan löytäminen epäonnistui" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "Tuntematon varmennusvirhe sähköpostipalvelimelta." #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Sähköpostin lähetys epäonnistui" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Sähköpostiyhteyden sulkeminen epäonnistui" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "Sähköpostitus onnistui" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Ei voida lähettää, vaaditut tiedot ovat puutteelliset" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Sähköpostipohjia ei löydy hakemistosta %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Vastaanottajaa ei määritelty, sähköpostia ei lähetetty" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Virheellinen koodaus sähköpostipohjassa %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Sähköpostipohjia ei löydy" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd raportoi levy täynnä\n" "\n" "Hei,\n" "\n" "SABnzbd on lopettanut lataamasta, koska levy on lähes täynnä.\n" "Ole hyvä ja tee lisää tilaa ja jatka SABnzbd käsin.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "Varoitus: LOCALHOST on hämärä, käytä numeerista IP-osoitetta." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Palvelimen osoite \"%s:%s\" ei ole kelvollinen." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "Käyttäjä kirjautui sisään web-käyttöliittymään" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "Käyttäjä kirjautui sisään" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Istuntoavain puuttuu" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Virhe: Istuntoavain vaaditaan" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Virhe: Istuntoavain on virheellinen" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "API avain puuttuu, ole hyvä ja syötä Asetukset->Yleiset löytyvä api avain " "käyttämääsi kolmannen osapuolen ohjelmaan:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "API avain virheellinen, käytä Asetukset->Yleiset löytyvää api avainta " "käyttämääsi kolmannen osapuolen ohjelmaan:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Authentikointi puuttuu, ole hyvä ja syötä käyttäjänimi/salasana Asetukset-" ">Yleiset kolmannen osapuolen ohjelmaasi:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Kokeile uutta Glitter teemaa! Uusittu design on optimoitu työpöytä- ja " "mobiilikäyttäjille. Mene Asetukset -> Yleiset muuttaaksesi teemaa." #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
SABnzbd sammutus valmis.
Odota noin 5 sekuntia ja paina " "sitten alapuolella olevaa nappia.

Päivitä
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Syöte" #: sabnzbd/interface.py msgid "Daily" msgstr "Päivittäin" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "Maanantai" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Tiistai" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Keskiviikko" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Torstai" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Perjantai" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Lauantai" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Sunnuntai" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "ei käytössä" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Määrittämätön palvelin!" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Virheellinen parametri" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Takaisin" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "VIRHE:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Virheellinen arvo %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "pv" #: sabnzbd/misc.py msgid "h" msgstr "t" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Ei voi luoda kansiota %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "%s kansio: %s virhe käytettäessä" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Kohteen (%s) luominen epäonnistui" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Kohteen %s siirtäminen kohteeseen %s epäonnistui" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Virhe luotaessa SSL avainta ja sertifikaattia" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Käyttöoikeuksien muuttaminen epäonnistui kohteelle %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Ajetaan skripti" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Jälkikäsittely peruutettiin (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Skripti" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Purkaessa havaittiin liikaa pakkauskerroksia [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Yhdistetään" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Puutteellinen joukko yhdistettäviä tiedostoja" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Tiedostoliitos %s epäonnistui" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Virhe \"%s\" yhdistettäessä tiedostoja" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Virhe \"%s\" ajettaessa file_join kohteelle %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] Liitetty %s tiedostoa" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Purkaminen epäonnistui, %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Virhe \"%s\" purettaessa RAR tiedostoja" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Virhe \"%s\" ajettaessa rar_unpack kohteelle %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Kohteen %s poisto epäonnistui!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Yritetään purkaa rar arkistoa salasanalla \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Purkaminen epäonnistui, arkisto vaatii salasanan" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Puretaan" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Pura" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Purkaminen epäonnistui, %s ei löydy" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "VIRHE: kohdetta \"%s\" ei löydy" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Purkaminen epäonnistui, CRC virhe" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "VIRHE: CRC epäonnistui kohteessa \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "Purkaminen epäonnistui, kirjoitusvirhe tai levy täynnä?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "VIRHE: kirjoitusvirhe (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Purkaminen epäonnistui, polku on liian pitkä" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "VIRHE: polku liian pitkä (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Purkaminen epäonnistui, katso loki" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "VIRHE: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Käyttökelvoton RAR arkisto" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "Korruptoitunut RAR arkisto" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s tiedostoa kohteessa %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Virhe \"%s\" ajettaessa unzip() kohteelle %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Yritetään purkaa 7zip arkistoa salasanalla \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "7ZIP setti \"%s\" on puutteellinen, ei voida purkaa" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Ei voitu purkaa %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Pikatarkistetaan" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Korjaa" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Pikatarkistus OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Aloitetaan korjaus" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "" "Par varmennus epäonnistui kohteessa %s, mutta Pikatarkistus onnistui!" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Korjaus epäonnistui, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Virhe %s ajettaessa par2_repair setille %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Virhe \"%s\" ajettaessa par2_repair setille %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] PAR2 vastaanotti vääränlaiset asetukset, tarkista Asetukset->Muuttujat" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Varmennettiin ajassa %s, kaikki tiedostot kelvollisia" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Varmennetiin ajassa %s, vaatii korjauksen" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "Noudetaan %s lohkoa..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Noudetaan" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "Korjaaminen epäonnistui, ei tarpeeksi korjauslohkoja (%s puuttuu)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Korjataan" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Korjattiin ajassa %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Levy täynnä" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Varmennetaan" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Tarkistetaan" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Tämä palvelin ei salli SSL yhteyksiä tähän porttiin" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "Palvelin %s käyttää epäluotettavaa sertifikaattia [%s]" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Käynnistys/Sammutus" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "Lisätty NZB" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Jälkikäsittely aloitettu" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Lataus valmistunut" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Lataus epäonnistui" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Jono valmistunut" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Muut viestit" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Ei saatavilla" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Prowl viestin lähetys epäonnistui" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Virheellinen vastaus Pushoverilta (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Pushover viestin lähetys epäonnistui" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Virheellinen vastaus Pushbulletilta (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Pushbullet viestin lähetys epäonnistui" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "Skripti palautti lopetuskoodin %s ja tulosteen \"%s\"" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "Ilmoitusskriptiä \"%s\" ei ole olemassa" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "Windows-ilmoituksen lähetys epäonnistui" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "" "Vanhan version jono havaittiin, käytä Tila->Korjaa muuntaaksesi jonon" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Ei-tuettu jonotiedosto löytyi, ei voida jatkaa" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Virhe ladattaessa %s, korruptoitunut tiedosto havaittu" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "" "NZB uudelleenkäynnistys epäonnistui ensimmäisen tarkistuksen jälkeen (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB lisätty jonoon" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Tuntematon koodaus" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Tiedosto %s on tyhjä, ohitetaan" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Virhe tuotaessa %s tiedostoa kohteesta %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Keskeneräinen NZB tiedosto %s" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Virheellinen NZB tiedosto %s, ohitetaan (syy=%s, rivi=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Tyhjä NZB tiedosto %s" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Ohitetaan kaksoiskappale NZB \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Keskeytetään kaksoiskappale NZB \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Peruutettu, ei voi valmistua" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "KAKSOISKAPPALE" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "SALATTU" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "LIIAN SUURI" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "KESKENERÄINEN" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "EI TOIVOTTU" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "SUODATETTU" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "ODOTA %s sekuntia" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "LEVITETÄÄN %s min" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Ladattiin ajassa %s keskilatausnopeudella %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Ikä" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s artikkelia oli väärin muotoiltuja" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s artikkelia puuttui" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s artikkelissa oli ei-vastaavia kaksoiskappaleita" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s artikkelia poistettiin" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Virhe tuotaessa %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Varoitukset" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Toimeton" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Asetukset" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Jono" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Tyhjennä jono" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Historia" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Tyhjennä historia" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Nopeusrajoitus" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Keskeytä" #: sabnzbd/osxmenu.py msgid "min." msgstr "min." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Jatka" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Tarkista vahdittu kansio" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Lue kaikki RSS syötteet" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Valmistuneet-kansio" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Lataukset-kansio" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Vianmääritys" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Käynnistä uudelleen" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Käynnistä uudelleen ilman kirjautumista" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Lopeta" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Vie ensimmäiset 10 kohdetta jonoon" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Tyhjä" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Vie viimeiset 10 kohdetta historiaan" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Uusi versio saatavilla" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Mene velhoon" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Pysäytetään..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Ongelma" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd tarvitsee vapaan tcp/ip portin sisäiselle web-" "palvelimelleen.
\n" " Porttia %s kohteessa %s yritettiin käyttää , mutta se ei ollut " "vapaana.
\n" " Jokin toinen ohjelmisto käyttää porttia tai SABnzbd on jo " "käynnissä.
\n" "
\n" " Ole hyvä ja uudelleenkäynnistä SABnzbd toisella porttinumerolla." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "Jos saat tämän virhesanoman uudestaan, kokeile toista numeroa.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd tarvitsee vapaan tcp/ip portin sisäiselle web-" "palvelimelleen.
\n" " Olet määritellyt epäkelvon osoitteen.
\n" " Turvalliset arvot ovat localhost ja 0.0.0.0
\n" "
\n" " Ole hyvä ja uudelleenkäynnistä SABnzbd kunnollisella isäntäosoitteella." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd havaitsi tallennettua tietoa toisesta SABnzbd versiosta
\n" " mutta ei voi uudelleenkäyttää tietoja toisesta ohjelmasta.

\n" " Haluat ehkä ladata jonon loppuun toisella ohjelmallasi.

\n" " Tämän jälkeen, käynnistä ohjelma \"--clean\" muuttujalla.
\n" " Tämä tyhjentää nykyisen jonon ja historiasi!
\n" " SABnzbd luki tiedostoa \"%s\"." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd ei löydä sen web-käyttöliittymän tiedostoja polusta %s.
\n" " Ole hyvä ja asenna ohjelma uudelleen.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd havaitsi vakavan virheen:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd havaitsi, että tiedosto sqlite3.dll puuttuu.

\n" " Jotkin huonosti suunnitellut viruksentorjunta ohjelmistot poistavat " "tämän tiedoston.
\n" " Tarkista virustorjunta ohjelmistosi, yritä asentaa SABnzbd uudelleen ja " "valita virustorjunta ohjelmistosi valmistajalle.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Paina Windows-nappia+R ja kirjoita seuraava rivi (esimerkki):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Avaa pääte ja kirjoita rivi (esimerkki):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Ohjelma ei käynnistynyt!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Vakava virhe" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "Selainta ei voida käynnistää, todennäköisesti ei löydy" #: sabnzbd/panic.py msgid "Access denied" msgstr "Ei käyttöoikeutta" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Virhe %s: Syötä kelvollinen käyttäjänimi ja salasana." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "Lataaminen saattaa epäonnistua, vain %s osaa %s osasta saatavilla" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Lataus epäonnistui - Ei ole palvelimilla" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Jälkikäsittelyä ei suoritettu, koska varmennus epäonnistui" #: sabnzbd/postproc.py msgid "Moving" msgstr "Siirretään" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "Lähetettiin %s jonoon" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Virhe uudelleennimettäessä \"%s\" nimelle \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Tiedostojen siirto epäonnistui" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Ajetaan käyttäjän skripti %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "Ajettiin %s" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Skriptin lopetuskoodi on %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Lisää" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Jälkikäsittely epäonnistui kohteelle %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "katso lokitiedosto" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Lataus epäonnistui" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "%s puhdistaminen epäonnistui." #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Virhe poistettaessa työkansiota (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Lataus valmistui" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Ei voitu luoda lopullista kansiota %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Jälkikäsittely" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Ei par2 arkistoja" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Yritetään SFV varmennusta" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Jotkin tiedostot eivät varmentuneet \"%s\" kanssa" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Varmennettiin onnistuneesti SFV tiedostojen avulla." #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "Yritetään RAR-pohjaista varmennusta" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "[%s] RAR-pohjainen varmennus epäonnistui: %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "Salasanasuojattu" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "RAR arkistot varmennettiin onnistuneesti" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "RAR arkistoja ei voitu varmentaa" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "%s poistaminen epäonnistui" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Järjestelmän lepotilaan laittaminen epäonnistui" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Järjestelmän valmiustilaan laittaminen epäonnistui" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Virhe sammutettaessa järjestelmää" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "Indeksoijan id:tä (%s) ei löydetty arviointitiedostolle" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Palvelimen osoite" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "API avain" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Virheellinen RSS syötteen kuvaus \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "RSS noutaminen epäonnistui kohteesta %s: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Ei ole käyttöoikeutta syötteeseen %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "Palvelinpään virhe (virhekoodi %s); ei voitu noutaa %s kohteesta %s" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "Palvelin %s käyttää epäluotettavaa HTTPS sertifikaattia" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "RSS syöte %s oli tyhjä" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Puutteellinen syöte" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Tyhjä RSS kohde löytyi (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Näytä käyttöliittymä" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Avaa valmistuneet-kansio" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Sammuta" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Jäljellä" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Lisää NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Virheellinen ajastus %s kohteessa %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Tuntematon toiminto: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Ajastettu tuntemattomalle palvelimelle %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Lataa" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Yhdistä tiedostot" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Lähde" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Palvelimet" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Epäonnistui" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Epäonnistunut" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "Odotetaan" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Korjataan..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Puretaan..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Siirretään..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Ajetaan skripti..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Noudetaan ylimääräiset lohkot..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Pikatarkistus..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Varmennetaan..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Ladataan" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "Levitysviive" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Toisto" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Toiminto" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Parametrit" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Tehtävä" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "poista palvelin käytöstä" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "ota palvelin käyttöön" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Nopeusrajoitus" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Keskeytä kaikki" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Keskeytä jälkikäsittely" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Jatka jälkikäsittelyä" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Lue RSS syötteet" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Poista epäonnistuneet lataukset" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Poista valmistuneet lataukset" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Keskeytä alhaisen prioriteetin lataukset" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Keskeytä normaalin prioriteetin lataukset" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Keskeytä korkean prioriteetin lataukset" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Jatka alhaisen prioriteetin lataukset" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Jatka normaalin prioriteetin lataukset" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Jatka korkean prioriteetin lataukset" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Ota latausrajoituksen hallinta käyttöön" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Ota latausrajoituksen hallinta pois käytöstä" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Ei käytössä" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Erittäin vähäinen" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Kohtalainen" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normaali" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Korkea" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Hälytys" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Matala" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "Mt" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "Gt" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "tunti" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "tuntia" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "minuutti" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "minuuttia" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "sekunti" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "sekuntia" #: sabnzbd/skintext.py msgid "day" msgstr "päivä" #: sabnzbd/skintext.py msgid "days" msgstr "päivää" #: sabnzbd/skintext.py msgid "week" msgstr "viikko" #: sabnzbd/skintext.py msgid "Month" msgstr "Kuukausi" #: sabnzbd/skintext.py msgid "Year" msgstr "Vuosi" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Kuukauden päivä" #: sabnzbd/skintext.py msgid "This week" msgstr "Tällä viikolla" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Tässä kuussa" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "Tänään" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Yhteensä" #: sabnzbd/skintext.py msgid "on" msgstr "käytössä" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parametrit" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Python versio" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Kotisivu" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "tai" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Isäntä" #: sabnzbd/skintext.py msgid "Comment" msgstr "Kommentti" #: sabnzbd/skintext.py msgid "Send" msgstr "Lähetä" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Peruuta" #: sabnzbd/skintext.py msgid "Other" msgstr "Muu" #: sabnzbd/skintext.py msgid "Report" msgstr "Ilmoita" #: sabnzbd/skintext.py msgid "Video" msgstr "Video" #: sabnzbd/skintext.py msgid "Audio" msgstr "Ääni" #: sabnzbd/skintext.py msgid "Not used" msgstr "Ei käytössä" #: sabnzbd/skintext.py msgid "or less" msgstr "tai vähemmän" #: sabnzbd/skintext.py msgid "Log in" msgstr "Kirjaudu sisään" #: sabnzbd/skintext.py msgid "Log out" msgstr "Kirjaudu ulos" #: sabnzbd/skintext.py msgid "Remember me" msgstr "Muista minut" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "Automaattinen usenet lataustyökalu" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Tallenna" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Oletko varma?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Poistetaanko kaikki ladatut tiedostot?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Alkuun" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Asetukset" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Tila" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Ohje" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Foorumi" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "Ongelmat" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "Tue projektia, lahjoita!" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Yleiset" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Kansiot" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Muuttujat" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Ajastus" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Ilmoitukset" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "Sähköposti" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Kategoriat" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Lajittelu" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Erikoisasetukset" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Etsi" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Lataukset-kansio" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "KESKEYTETTY" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "%s artikkelia välimuistitettu (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Kuorma" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Uusi versio %s saatavilla osoitteesta" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Oletko varma, että haluat sammuttaa SABnzbdn?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Lisää" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Lisää tiedostosta" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Kategoria" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Käsitellään" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Prioriteetti" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Korjaa" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Pura" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Poista" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "U" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "D" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Pakota" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Pysäytä" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "Syötä osoite" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "Kun jono on tyhjä" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Sammuta tietokone" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "Lepotila" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Horrostila" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Sammuta SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Nopeusrajoitus" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Keskeytä ajaksi" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Järjestys" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Nimi" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "Aikaa jäljellä" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "IKÄ" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Poista" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Yritä uudelleen" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Toiminnot" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Skriptit" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Poistetaanko kaikki kohteet jonosta?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Puhdista NZBt" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Puhdista NZBt & poista tiedostot" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Yritä uudelleen kaikki epäonnistuneet lataukset" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Poista NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Poista NZB ja tiedostot" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "/" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Puuttuvat artikkelit" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Latausrajoitusta jäljellä" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "käsikäyttöinen" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Resetoi latausrajoitus nyt" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Poistetaanko kaikki valmistuneet kohteet historiasta?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Piilota yksityiskohdat" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Näytä yksityiskohdat" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Näytä epäonnistuneet" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Näytä kaikki" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Koko" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Puhdista epäonnistuneet NZBt" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Puhdista epäonnistuneet NZBt & poista tiedostot" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Puhdista valmistuneet NZBt" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "Puhdista NZBt nykyiseltä sivulta" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "Vaihtoehtoinen täyte-NZB" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Polku" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Yritä uudelleen kaikki epäonnistuneet" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Yritä uudelleen kaikki" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus/roskaposti" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "Säilytyksen ulkopuolella" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Muu ongelma" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Pakota yhteyden katkaisu" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Tämä lähettää testiviestin sähköpostiosoitteeseesi." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Näytä loki" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Testaa sähköpostia" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Lokiinkirjaus" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Virheet/varoitukset" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ Tiedot" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ Debug" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Yhteydet" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Viimeisimmät varoitukset" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "tyhjennä" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Poista esto" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Artikkelin tunniste" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Tiedostojoukko" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Milloin" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Tyyppi" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Käytössä" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Hallintapaneeli" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Yhteys epäonnistui!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Paikallinen IPv4 osoite" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Julkinen IPv4 osoite" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "IPv6 osoite" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Nimipalvelin / DNS-selvitys" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "Prosessorin malli" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "Järjestelmän suorituskyky (Pystone)" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Latauskansion nopeus" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Valmistuneet-kansion nopeus" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Kirjoitusnopeus" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "" "Ei voitu kirjoittaa. Varmista, että sinulla on kirjoitusoikeus kansioon." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Paina Toista testi -painiketta alapuolella määrittääksesi" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Toista testi" #: sabnzbd/skintext.py msgid "Config File" msgstr "Asetustiedosto" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Käytetty välimuisti" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Tämä uudelleenkäynnistää SABnzbdn.
Käytä sitä kun luulet ohjelman " "toimivan epävakaasti.
Lataaminen keskeytyy uudelleenkäynnistyksen " "ajaksi ja jatkuu ohjelman käynnistyttyä." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" "
Jos tunnistautuminen on käytössä, sinun täytyy kirjautua sisään " "uudestaan." #: sabnzbd/skintext.py msgid "Advanced" msgstr "" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Latauskansiossa on orpoja latauksia.
Voit valita niiden poistamisen " "(sisältäen tiedostot) tai voit lähettää ne takaisin jonoon." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "\"Korjaa\" painike käynnistää SABnzbd uudelleen ja luo jonon
sisällön " "täydellisesti uudelleen, säilyttäen jo ladatut tiedostot.
Tämä muuttaa " "jonon järjestystä." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Muutoksia ei ole tallennettu ja ne menetetään." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" "Istunto vanhenee kun IP-osoite vaihtuu tai SABnzbd käynnistetään uudelleen." #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Unzip käytössä" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "7zip käytössä" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" "Varmennetut (SSL) yhteydet SABnzbdltä uutispalvelimille ja HTTPS " "verkkosivuille salataan, mutta palvelimen identiteetin varmennus käyttäen " "sen omaa sertifikaattia ei ole mahdollista. Siihen vaaditaan Python 2.7.9+, " "OpenSSL 1.0.2+ ja ajan tasalla olevat paikalliset CA sertifikaatit." #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" #: sabnzbd/skintext.py msgid "Version" msgstr "Versio" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Käynnissäoloaika" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Varmuuskopioi" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Lue Wikin ohjeet tähän!" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Käynnistetään SABnzbd uudelleen..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Muutokset vaativat SABnzbdn uudelleenkäynnistyksen!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "SABnzbd web-palvelin" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "SABnzbd isäntä" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Osoite jota SABnzbdn tulisi kuunnella." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "SABnzbd portti" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Portti jota SABnzbdn tulisi kuunnella." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Web-käyttöliittymä" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Valitse teema." #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "SABnzbd käyttäjänimi" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Vaihtoehtoinen käyttäjänimi todennukseen." #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "SABnzbd salasana" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Vaihtoehtoinen salasana todennukseen." #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "HTTPS käytössä" #: sabnzbd/skintext.py msgid "not installed" msgstr "ei asennettu" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Ota käyttöön käyttöliittymän käyttäminen HTTPS-osoitteesta." #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "HTTPS portti" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Jos tyhjä, oletusportti kuuntelee ainoastaan HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "HTTPS sertifikaatti" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Tiedostonimi tai polku HTTPS sertifikaattiin." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" "Luo uusi itse allekirjoitettu sertifikaatti ja avain. Vaatii SABnzbd " "uudelleenkäynnistyksen!" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "HTTPS avain" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Tiedostonimi tai polku HTTPS avaimeen." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "HTTPS ketjun sertifikaatit" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Tiedostonimi tai polku HTTPS ketjuun." #: sabnzbd/skintext.py msgid "Tuning" msgstr "Hienosäätö" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "RSS tarkistusväli" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Tarkistusväli (minuutteina, vähintään 15). Ei ole aktiivinen jos käytät " "Ajastinta!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Suurin latausnopeus" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Latausnopeuden prosenttiosuus" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "" "Kuinka monta prosenttia latausnopeudesta SABnzbd saa käyttää, esim. 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Välimuistirajoitus artikkeleille" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Välimuistita artikkelit muistissa levytapahtumien vähentämiseksi.
Tavuina, vaihtoehtoisesti lisää pääte K,M,G. Esimerkiksi: \"64M\" tai " "\"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Puhdistuslista" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Lista tiedostopäätteistä jotka poistetaan latauksen valmistuttua.
Esimerkiksi: nfo tai nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Tallenna muutokset" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "Palauta oletusasetukset" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Nollaa" #: sabnzbd/skintext.py msgid "Language" msgstr "Kieli" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Valitse web-käyttöliittymän kieli." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" "Auta meitä kääntämään SABnzbd sinun kielellesi!
Käännä tai muokkaa " "olemassaolevia käännöksiä täällä:" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "" "Tämä avain antaa kolmannen osapuolen ohjelmille täyden pääsyn SABnzbd-" "ohjelmaan." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "NZB avain" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "Tämä avain antaa kolmannen osapuolen ohjelmille oikeudet lisätä NZB-" "tiedostoja SABnzbd-ohjelmaan." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Luo uusi avain" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "API avaimen QR-koodi" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Lista paikallisista verkko-osoitealueista" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Kaikki paikalliset verkko-osoitteet alkavat näillä etuliitteillä (yleensä " "\"192.168.1.\")" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Ulkoinen ohjelman käyttö" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" #: sabnzbd/skintext.py msgid "No access" msgstr "Ei pääsyä" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Lisää NZB tiedostot " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (ei asetuksia)" #: sabnzbd/skintext.py msgid "Full API" msgstr "Täysi API" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Täysi Web-käyttöliittymä" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "Vain ulkoinen käyttö vaatii kirjautumisen" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "HUOM: Kansiot luodaan automaattisesti tallennuksen yhteydessä. Voit " "käyttää täydellisiä polkuja jos haluat tallentaa oletuskansioiden " "ulkopuolelle." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Käyttäjähakemistot" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Selaa" #: sabnzbd/skintext.py msgid "In" msgstr "Kohteessa" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Väliaikaiset lataukset kansio" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Sijainti jonne tallennetaan latauksessa olevat kohteet ennen käsittelyä.
Voidaan muuttaa vain kun jono on tyhjä." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Pienin vapaan tilan määrä väliaikaisille latauksille" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Keskeytä automaattisesti kun vapaan tilan määrä on vähemmän kuin tämä " "arvo.
Tavuina, mutta voit laittaa perään K,M,G,T kirjaimen. " "Esimerkiksi: \"800M\" tai \"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Valmistuneet kansio" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Sijainti jonne tallennetaan valmistuneet ja täysin käsitellyt ladatut " "kohteet.
Käyttäjän asettamat kategoriat voivat kumota tämän." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Käyttöoikeudet valmistuneille latauksille" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Aseta käyttöoikeusmalli valmistuneille tiedostoille/kansioille.
Oktaalilukuna. Esimerkiksi: \"755\" tai \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Vahdittu kansio" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Kansio jota vahditaan .nzb tiedostojen varalta.
Etsii .nzb " "tiedostoja myös .zip .rar ja .tar.gz arkistojen sisältä." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Vahditun kansion tarkistusväli" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Skannausväli sekunteina .nzb tiedostoille." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Sähköpostipohjien kansio" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Kansio joka sisältää käyttäjän luomat sähköpostipohjat." #: sabnzbd/skintext.py msgid "Password file" msgstr "Salasanatiedosto" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Tiedosto joka sisältää kaikki salasanat joita kokeillaan salattuihin RAR " "tiedostoihin." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Järjestelmäkansio" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Hallinnollinen kansio" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Sijainti jonne tallennetaan jonon hallinnan ja historian tietokannat.
Voidaan muuttaa vain jonon ollessa tyhjä." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "Tiedostoja ei tulla siirtämään. Vaatii SABnzbd " "uudelleenkäynnistyksen!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Lokikansio" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Sijainti jonne SABnzbd ohjelman lokitiedostot tallennetaan.
Vaatii " "SABnzbd uudelleenkäynnistyksen!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr ".nzb varmuuskopiokansio" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Sijainti jonne .nzb tiedostot tallennetaan." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Oletuskansio" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Lataa kaikki par2 tiedostot" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Rekursiivinen purkaminen käytössä" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Purkaa arkistot (rar, zip, 7z) arkistojen sisältä." #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Ohita kansiot arkistojen sisällä" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Kaikki tiedostot menevät yhteen kansioon." #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Hae artikkelit vain jonon huipulta" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Laita päälle jos haluat ohjelman käyttävän vähemmän muistia. Ota pois päältä " "jos haluat estää hitaiden latauksien aiheuttavan ruuhkaa jonossa." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Jälkikäsittele vain onnistuneet lataukset" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "" "Suorittaa jälkikäsittelyn vain niille latauksille jotka läpäisevät kaikki " "PAR2 tarkistukset." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Toiminto kun salattu RAR havaitaan" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "Jos valitsit \"Keskeytä\", sinun täytyy antaa salasana ja jatkaa sen jälkeen " "lataamista." #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Tunnista päällekkäiset lataukset" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Tunnista identtiset jaksot sarjassa" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Hylkää" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Peruuta" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Toiminto kun havaitaan ei toivottu tiedostopääte" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "Toiminto kun ei toivottu tiedostopääte havaitaan RAR arkistossa" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Ei toivotut tiedostopäätteet" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Lista ei toivotuista tiedostopäätteistä. Esimerkiksi: exe tai exe, " "com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "SFV-pohjaiset tarkistukset käytössä" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Suorittaa ylimääräisen varmennuksen SFV tiedostojen avulla." #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Käyttäjän skripti voi merkitä latauksen epäonnistuneeksi" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Kun käyttäjän skripti palauttaa nollasta poikkeavan koodin, lataus merkitään " "epäonnistuneeksi." #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "Epäonnistuessa, kokeile vaihtoehtoista NZB:tä" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "" "Jotkin palvelimet tarjoavat vaihtoehtoisen NZB:n kun lataus epäonnistuu." #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Kansion uudelleennimeäminen käytössä" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Käyttää väliaikaisia nimiä kun jälkikäsittely on käynnissä. Poista käytöstä " "jos järjestelmäsi ei toimi oikein asetuksen ollessa päällä." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Esijonon käyttäjän skripti" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Käytetään ennen NZB lisäämistä jonoon." #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Ylimääräiset PAR2 parametrit" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Nice muuttujat" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "IONice muuttujat" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Katkaise yhteys kun jono on tyhjä" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "" "Katkaise yhteys Usenet palvelimeen/palvelimiin kun jono on tyhjä tai tila on " "keskeytetty." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Järjestä iän mukaan" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Järjestelee kohteet (keskimääräisen) iän mukaan." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" "Lähetykset tauotetaan kunnes ne ovat vähintään näin vanhoja. Prioriteetin " "asettaminen pakottamiselle ohittaa asetetun viiveen." #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Tarkista uusi versio" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Tarkistaa viikottain uusimman SABnzbd version." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "Myös testiversiot" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Korvaa välilyönnit kansionimessä" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Korvaa välilyönnit alaviivoilla kansionimissä." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Korvaa pisteet kansionimessä" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Korvaa pisteet välilyönneillä kansionimissä." #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Windows yhteensopivuus" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "Palvelimille: varmistaa että nimet ovat Windows yhteensopivia." #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Käynnistä selain käynnistyksen yhteydessä" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Käynnistää oletusselaimen kun SABnzbd käynnistetään." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Keskeytä lataus jälkikäsittelyn ajaksi" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Keskeyttää lataamisen kun jälkikäsittely alkaa ja jatkaa lataamista kun se " "lopetetaan." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Ohita näytteet" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Ohittaa näytetiedostot (esim. videonäytteet)." #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Poista lataamisen jälkeen" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "HTTPS sertfikaatin varmennus" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" "Varmenna sertifikaatit yhdistettäessä indeksoijiin ja RSS-lähteisiin HTTPS " "protokollan avulla." #: sabnzbd/skintext.py msgid "Server" msgstr "Palvelin" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Jälkikäsittely" #: sabnzbd/skintext.py msgid "Naming" msgstr "Nimeäminen" #: sabnzbd/skintext.py msgid "Quota" msgstr "Latausrajoitus" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indeksoidaan" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Kuinka paljon voidaan ladata tässä kuussa (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Resetointipäivä" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "Minä päivänä kuusta tai viikosta (1=Maanantai) palveluntarjoajasi resetoi " "rajoituksen? (Voit syöttää kellonajan perään hh:mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Jatka automaattisesti" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "Pitäisikö latauksia jatkaa kun latausrajoitus on resetoitu?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Latausrajoituksen pituus" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "Resetoidaanko rajoitus joka päivä, viikko vai kuukausi?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Tarkista ennen lataamista" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "Yritä ennustaa latauksen valmistuminen ennen lataamista (hitaampi!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "SSL-salaus" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "Lisää suorituskykyä pakottamalla alhaisempi SSL-suojaustaso." #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Enimmäismäärä uudelleenyrityksille" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Enimmäismäärä uudelleenyrityksiä yksittäiselle palvelimelle." #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Peruuta lataukset jotka eivät voi valmistua" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Peruutetaan lataus, jos ladattaessa huomataan liikaa tiedostoja puuttuvan" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Suodatus päälle" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Latauksien toiminto suodatinsääntöjen mukaan." #: sabnzbd/skintext.py msgid "Abort If" msgstr "Peruuta jos" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Muutoin keskeytä jos" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Videon suosio" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Äänen suosio" #: sabnzbd/skintext.py msgid "Spam" msgstr "Spämmi" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Vahvistettu" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Enemmän alapeukkuja kuin yläpeukkuja" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Nimen avainsanat" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Pilkulla erotettu lista" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Palvelimen kuormantasaus" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Estä kuormantasaus" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Salli kuormantasaus" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Salli kuormantasaus IPv6 optimoinnille" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "" "Hyödyllinen jos uutispalvelimella on enemmän kuin yksi IPv4/IPv6 osoite" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Lisää palvelin" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Palvelimen kuvaus" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Portti" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Käyttäjänimi" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Salasana" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Aikakatkaisu" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Säilytysaika" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "Sertifikaatin varmennus" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Ei käytössä" #: sabnzbd/skintext.py msgid "Minimal" msgstr "" #: sabnzbd/skintext.py msgid "Strict" msgstr "Tiukka" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 on suurin prioriteetti, 100 on pienin prioriteetti" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Vaihtoehtoinen" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Ota käyttöön" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Poista palvelin" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Testaa palvelinta" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Nollaa laskurit" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Testataan pavelimen tietoja..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Kaista" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Lähetä ryhmä" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Lähettää ryhmäkomennon ennen artikkeleiden pyytämistä." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Käytä tätä palvelinta vain näihin kategorioihin." #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" "Ainoallakaan käytössä olevalla palvelimella ei ole 'Oletus' kategoriaa " "valittuna. Jonossa olevia latauksia, joita ei ole lisätty johonkin " "palvelimen kategoriaan ei tulla lataamaan." #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Henkilökohtaiset huomautukset" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Lisää ajastus" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Nykyiset ajastukset" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "Valintaruutu syötteen nimen vieressä täytyy olla valittuna jotta syöte on " "päällä ja uusia kohteita tarkistetaan automaattisesti.
Kun syöte " "lisätään, siitä lisätään vain uusia kohteita eikä niitä jotka ovat jo " "julkaistu syötteessä ellet paina \"Pakota lataus\" -painiketta." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Lue syöte" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Pakota lataus" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Suodata" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Hyväksy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Hylkää" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Vaatii" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "VaadittuCat" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Vähintään" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Enintään" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "Alkaen SxxExx" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Vastaa" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Ei vastaavuutta" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Ladattu" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Lue kaikki syötteet nyt" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "Sähköposti-ilmoitus onnistuneesta latauksesta" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Ei koskaan" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Aina" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Vain virheet" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Levy täynnä ilmoitukset" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "Lähetä sähköposti kun levy on täynnä ja SABnzbd on keskeytetty." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Lähetä RSS ilmoitukset" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "Lähetä sähköpostia kun RSS syötteestä lisätään latauksia jonoon." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "SMTP-palvelin" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Sähköpostin lähtevän postin palvelimen osoite." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "Sähköpostin vastaanottaja" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "Sähköpostiosoite johon viestit lähetetään." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "Sähköpostin lähettäjä" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Kuka näytetään viestin lähettäjänä?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "VAIHTOEHTOINEN tilin käyttäjänimi" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Kirjautumisen vaativalle sähköpostille, tilin käyttäjänimi." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "VAIHTOEHTOINEN tilin salasana" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Kirjautumisen vaativalle sähköpostille, tilin salasana." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Growl käytössä" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Lähetä ilmoitukset Growliin" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Käytä vain Growl etäpalvelimelle (isäntä:portti)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Palvelimen salasana" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Vaihtoehtoinen salasana Growl palvelimelle" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "NotifyOSD käytössä" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Lähetä ilmoitukset NotifyOSD:hen" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Ilmoituskeskus" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Lähetä ilmoitukset ilmoituskeskukseen" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Windows-ilmoitukset käytössä" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Windows-ilmoitukset" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "IlmoitusOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Prowl ilmoitukset käytössä" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Vaatii Prowl-tilin" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "Prowl API avain" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Prowlin henkilökohtainen API avain (pakollinen)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Pushover ilmoitukset käytössä" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Vaatii Pushover tilin" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Ohjelman token" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Ohjelman token (pakollinen)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Käyttäjän avain" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Käyttäjän avain (pakollinen)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Laitteet" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Laitteet joihin viesti lähetetään" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Pushbullet ilmoitukset käytössä" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Vaatii Pushbullet tilin" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Henkilökohtainen API avain" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Henkilökohtainen Pushbullet API avain (pakollinen)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Laite" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Laite johon viesti lähetetään" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "Ilmoitusskripti" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "Ilmoitusskripti päällä" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "Suorittaa käyttäjän skriptin" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "Mikä skripti suoritetaan ilmoitukselle?" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" "Indeksoijat voivat tarjota kategorian NZB tiedoston sisällä jonka SABnzbd " "yrittää vastata johonkin esimääriteltyyn kategoriaan. Voit lisäksi lisätä " "sanoja \"Indeksoijan kategoriat / ryhmä\" -kohtaan vastaamaan useampia " "kategorioita. Käytä pilkkuja sanojen erottamiseen. Jokerimerkit ovat " "tuettuna.
Lisätietoja löytyy Wikistä." #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Polun päättäminen tähteen * estää latauskohtaisten kansioiden luomisen." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Suhteelliset kansiot jotka perustuvat" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Kansio/Polku" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "Indeksoijan kategoriat / ryhmä" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Sarjojen lajittelu" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "TV lajittelu käytössä" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Mallin avain" #: sabnzbd/skintext.py msgid "Clear" msgstr "Tyhjennä" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "" #: sabnzbd/skintext.py msgid "Presets" msgstr "Esiasetukset" #: sabnzbd/skintext.py msgid "Example" msgstr "Esimerkki" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Elokuvien lajittelu käytössä" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Pidä irralliset lataukset ylimääräisissä kansioissa" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Kategoriat joita koskee" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Merkitys" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Malli" #: sabnzbd/skintext.py msgid "Result" msgstr "Tulos" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Tuotantokausi kansio" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Tuotantokausi kansio" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Jakso kansio" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Jakso kansio" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Nimi" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Elokuvan nimi" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Elokuvan.nimi" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Elokuvan_nimi" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Ohjelman nimi" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Ohjelman.nimi" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Ohjelman_nimi" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Tuotantokauden numero" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Jakson numero" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Jakson nimi" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Jakson.nimi" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Jakson_nimi" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Tiedostotunniste" #: sabnzbd/skintext.py msgid "Extension" msgstr "Tunniste" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Osan numero" #: sabnzbd/skintext.py msgid "Decade" msgstr "Vuosikymmen" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Alkuperäinen tiedostonimi" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Pienaakkoset" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEKSTI" #: sabnzbd/skintext.py msgid "text" msgstr "teksti" #: sabnzbd/skintext.py msgid "file" msgstr "tiedosto" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Lajittelumerkkijono" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Moniosainen selite" #: sabnzbd/skintext.py msgid "In folders" msgstr "Kansioissa" #: sabnzbd/skintext.py msgid "No folders" msgstr "Ei kansioita" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Päivämäärän lajittelu" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Päivämäärän lajittelu käytössä" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Ohjelman nimi kansio" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "Vuosittaiset-Kuukausittaiset kansiot" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Päivittäiset kansiot" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "kirjainkokoa säätävä" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Käsitellyt tulokset" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Harvoin käytetyt asetukset. Paina Ohje-painiketta Wiki-sivustolle " "päästäksesi, jotta saat tietää näiden tarkoituksen ja ohjeet " "käyttöön.
Älä muuta ennen Wikin lukemista, koska näiden muuttamisella voi " "olla vakavia sivuvaikutuksia.
Oletusarvot ovat kirjoitettuna sulkeiden " "sisään." #: sabnzbd/skintext.py msgid "Values" msgstr "Arvot" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "NZB tietojen muokkaus" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Poista" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Ylin" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Ylös" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Alas" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Alin" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Kaikki" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Käänteinen" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Tiedostonimi" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Otsikko" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Valinta" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Keskeytä 5:ksi minuutiksi" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Keskeytä 15:ksi minuutiksi" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Keskeytä 30:ksi minuutiksi" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Keskeytä tunniksi" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Keskeytä 3:ksi tunniksi" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Keskeytä 6:ksi tunniksi" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "jäljellä" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Vapaa tila" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Väliaikaiskansio" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Monioperaatiot" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Paina vaihto-näppäintä pohjassa valitaksesi alueen" #: sabnzbd/skintext.py msgid "Check all" msgstr "Valitse kaikki" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Uudelleenkäynnistä SABnzbd" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Tilan ja käyttöliittymän asetukset" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Tai vedä ja pudota tiedostot tähän ikkunaan!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Menetettiin yhteys SABnzbd:hen..." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "" "Mikäli SABnzbd käynnistetään uudelleen, tämä ruutu häviää automaattisesti!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "VAROITUS:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Nouda" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Päivitysväli" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Käytä yleisiä käyttöliittymän asetuksia" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Jonon pituusrajoitus" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Historian pituusrajoitus" #: sabnzbd/skintext.py msgid "Date format" msgstr "Päivämäärän muoto" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Ylimääräisen jonon sarake" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "Ylimääräinen historiasarake" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "sivu" #: sabnzbd/skintext.py msgid "Loading" msgstr "Ladataan" #: sabnzbd/skintext.py msgid "articles" msgstr "artikkeleita" #: sabnzbd/skintext.py msgid "Rename" msgstr "Uudelleennimeä" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Jonon korjaus" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Näytä aktiiviset yhteydet" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Orvot lataukset" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Lähetä takaisin jonoon" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Poista kaikki" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Yritä uudelleen kaikki" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Nouda NZB osoitteesta" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "Lähetä NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Vaihtoehtoisesti anna tiedostonimi" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Tiedostomuodot: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Lähetä" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Avaa tietoja sisältävä osoite" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Lähetetty. Kiitos!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Ei mitään valittuna!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Poista kaikki valitut tiedostot" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Piilota/näytä valmistuneet tiedostot" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Näytä skriptien loki" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Päivitys saatavilla!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" "LocalStorage (evästeet) on pois käytöstä selaimen asetuksista. " "Käyttöliittymän asetukset menetetään kun selain suljetaan!" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "" "Glitter-teemassa on muutamia (uusia) ominaisuuksia joista saatat pitää!" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Mukautettu" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "Tiivis käyttöliittymä" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "Välilehditetty käyttöliittymä
(erillinen jono ja historia)" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Nopeus" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Varmista jonon poistot" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Varmista historian poistot" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Kuinka pitkään tai mihin asti haluat keskeyttää? (englanniksi!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Valitettavasti emme ymmärtäneet tuota. Yritä uudelleen." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Keskeytä ajaksi..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Päivitä" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Järjestä iän mukaan Vanhin→Uusin" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Järjestä iän mukaan Uusin→Vanhin" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Järjestä nimen mukaan A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Järjestä nimen mukaan Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Järjestä koon mukaan Pienin→Suurin" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Järjestä koon mukaan Suurin→Pienin" #: sabnzbd/skintext.py msgid "Uploading" msgstr "Lähetetään" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "Pakotetaan yhteyden katkaisu" #: sabnzbd/skintext.py msgid "Removing job" msgstr "Poistetaan lataus" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "Poistetaan lataukset" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Edellinen" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Seuraava" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Puhdistetaanko historia?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Ota JavaScript käyttöön, jotta Plush toimii oikein!" #: sabnzbd/skintext.py msgid "Options" msgstr "Asetukset" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Keskeytetään kuinka moneksi minuutiksi?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Päävalikko" #: sabnzbd/skintext.py msgid "On Finish" msgstr "Valmistuessa" #: sabnzbd/skintext.py msgid "Sort" msgstr "Lajittele" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Järjestä iän mukaan(Vanhin→Uusin)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Järjestä iän mukaan(Uusin→Vanhin)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Järjestä nimen mukaan (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Järjestä nimen mukaan (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Järjestä koon mukaan (Pienin→Suurin)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Järjestä koon mukaan (Suurin→Pienin)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Puhdistetaanko jono?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Yritetäänkö uudelleen kaikki epäonnistuneet lataukset Historiassa?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Puhdista" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Enimmäisnopeus" #: sabnzbd/skintext.py msgid "Range" msgstr "Väli" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Käytä valittuihin" #: sabnzbd/skintext.py msgid "Everything" msgstr "Kaikki" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Päivitysväli" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Säiliön leveys" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "" "Tämä estää sisällön päivittämisen kun hiiren kursori on jonon päällä." #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Estä päivitykset kun hiiri on päällä" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Lähetä" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Lähetä: .nzb .rar .zip .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Edistyminen" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Ei tarpeeksi levytilaa latauksien valmistumiseen!" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Vapaana (Temp)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "EI TÖITÄ" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Lataukset" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Poista valmistuneet" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Poistetaanko kaikki epäonnistuneet historiasta?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Poista epäonnistuneet" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Yritetäänkö uudelleen kaikki epäonnistuneet lataukset?" #: sabnzbd/skintext.py msgid "Links" msgstr "Linkit" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Näytetään %s - %s tulosta %s tuloksesta" #: sabnzbd/skintext.py msgid "No results" msgstr "Ei tuloksia" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Näytetään yksi tulos" #: sabnzbd/skintext.py msgid "First" msgstr "Ensimmäinen" #: sabnzbd/skintext.py msgid "Last" msgstr "Viimeinen" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "Sähköposti lähetetty!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Ilmoitus lähetetty!" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Tallennetaan..." #: sabnzbd/skintext.py msgid "Saved" msgstr "Tallennettu" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Päälle/Pois Lisää NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "Kaksoisnäkymä1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "Kaksoisnäkymä2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Oletko varma, että haluat käynnistää SABnzbd uudelleen?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Piilota muokkausvalinnat" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Näytä muokkausvalinnat" #: sabnzbd/skintext.py msgid "Edit" msgstr "Muokkaa" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Aikaa jäljellä" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "SABnzbd pika-aloitus velho" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "SABnzbd versio" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Edellinen" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Palvelimen tiedot" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Syötä pääasiallisen usenet tarjoajasi tiedot." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Tarjoajasi sallimien yhteyksien lukumäärä." #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "Esim. 8 tai 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Valitse vain jos tarjoajasi sallii SSL yhteydet." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Klikkaa testataksesi syötettyjä tietoja." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Esim." #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "Asennus on nyt valmis!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd on nyt käynnissä taustalla." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "Selaimen tai sen välilehtien sulkeminen EI sammuta SABnzbd:tä." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "On suositeltavaa, että painat linkistä hiiren oikealla ja lisäät sen " "kirjanmerkkeihin. Sitten voit käyttää kirjanmerkkiä kun haluat käyttää " "SABnzbd ohjelmaa sen ollessa käynnissä taustalla." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Lisää ohjeita löytyy" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Siirry SABnzbd:hen" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Poistu SABnzbd:stä" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Käynnistä velho" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd ohjelmalla EI OLE MINKÄÄNLAISTA TAKUUTA.\n" "Tämä on ilmainen ohjelma ja olet vapaa levittämään sitä tiettyjen ehtojen " "ollessa voimassa.\n" "Se on lisensoitu GNU GENERAL PUBLIC LICENSE Versio 2 alaiseksi ja (oman " "valinnan mukaan) myös myöhempien versioiden.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "Jotta voit ladata usenetistä tarvitset tarjoajan. Palveluntarjoajasi saattaa " "tarjota sinulle sellaisen, mutta on suositeltavaa hankkia premium-tarjoaja." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "Eikö sinulla ole usenet tarjoajaa? Suosittelemme kokeilemaan %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Virhe noudettaessa TV tietoja (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Virhe uudelleennimettäessä: %s %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Samankaltaisen tiedoston uudelleennimeäminen epäonnistui: %s %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Palvelimen osoitetta ei voitu selvittää" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Luvaton käyttö" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "Tiedostoa ei ole palvelimella" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "OSOITTEENNOUTAJA KAATUI" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "NZB tiedostoa ei voida käyttää" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "Osoitteen nouto epäonnistui; %s" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "CRC virhe tiedostossa %s (%s -> %s)" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "Kansiota \"%s\" ei ole olemassa" #~ msgid "Initiating restart...
" #~ msgstr "Aloitetaan uudelleenkäynnistys...
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "PAR2 ohjelmaa ei löydy, korjaukset eivät ole mahdollista
" #~ msgid "Not matched" #~ msgstr "Ei vastaa" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "" #~ "Töitä jotka ovat merkitty '*' merkillä ei ladata automaattisesti uudelleen." #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "Työ \"%s\" lisättiin uudelleen jonoon" #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Erikoiskansioiden rekisteriavainten lukeminen epäonnistui" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Ei voida yhdistää rekisteripolkuun HKEY_CURRENT_USER." #~ msgid "Downloaded so far" #~ msgstr "Ladattu tähän mennessä" #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Ei voida avata rekisteriavainta \"%s\"." #~ msgid "Try again" #~ msgstr "Yritä uudelleen" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "" #~ "pyopenssl moduuli puuttuu, ole hyvä ja asenna se https käyttöä varten" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Purkaminen epäonnistui, nämä tiedostot puuttuvat:" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "Purkaminen epäonnistui, odotettua tiedostoa ei purettu" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Odotettu tiedosto: %s puuttuu => purkuvirhe?" #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Virhe tuotaessa OpenSSL moduulia. Yhdistetään EI-SSL kautta." #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Käyttämäsi UNRAR versio ei ole suositeltu, nouda oikea osoitteesta " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Virheelliset par2 arkistot, varmennus ja korjaus ei mahdollista" #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "" #~ "On todennäköistä, että käytössäsi on ZoneAlarm ja käyttöjärjestelmäsi on " #~ "Vista.
" #~ msgid "OK" #~ msgstr "OK" #~ msgid "You have no permisson to use port %s" #~ msgstr "Sinulla ei ole käyttöoikeuksia porttiin %s" #~ msgid "Get NZB" #~ msgstr "Nouda NZB" #~ msgid "KB/s" #~ msgstr "kt/s" #~ msgid "Queued" #~ msgstr "Jonossa" #~ msgid "Complete Dir" #~ msgstr "Valmistuneet-kansio" #~ msgid "WARNINGS" #~ msgstr "VAROITUKSET" #~ msgid "Download speed" #~ msgstr "Latausnopeus" #~ msgid " " #~ msgstr " " #~ msgid " or Report ID" #~ msgstr " tai Raportti ID" #~ msgid "Sort by age" #~ msgstr "Lajittele iän mukaan" #~ msgid "Sort by name" #~ msgstr "Lajittele nimen mukaan" #~ msgid "Sort by size" #~ msgstr "Lajittele koon mukaan" #~ msgid "Hide files" #~ msgstr "Piilota tiedostot" #~ msgid "Show files" #~ msgstr "Näytä tiedostot" #~ msgid "Remain/Total" #~ msgstr "Jäljellä/Yhteensä" #~ msgid "SQL Commit Failed, see log" #~ msgstr "SQL muutos epäonnistui, katso loki" #~ msgid "Main packet not found..." #~ msgstr "Pääpakettia ei löydy..." #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "" #~ "UNRAR ohjelmaa ei löydy, RAR-tiedostojen purkaminen ei ole mahdollista
" #~ msgid "Error: No secondary interface defined." #~ msgstr "Virhe: Toissijaista käyttöliittymää ei ole määritelty." #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd ei ole yhteensopiva kaikkien ohjelmistopalomuurien kanssa.
\n" #~ " %s
\n" #~ " Pahoittelumme, mutta emme voi ratkaista tätä yhteensopivuusongelmaa " #~ "juuri nyt.
\n" #~ " Ole hyvä ja lähetä valitus palomuurin toimittajallesi.
\n" #~ "
\n" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd tarvitsee vapaan tcp/ip portin sisäiselle web-" #~ "palvelimelleen.
\n" #~ " Porttia %s kohteessa %s yritettiin käyttää , mutta tilillä jolla SABnzbd " #~ "käynnistettiin ei ollut oikeuksia käyttää sitä.
\n" #~ " OSX ja Linux järjestelmissä normaalien käyttäjien tulee käyttää portteja " #~ "jotka ovat suurempia kuin 1023.
\n" #~ "
\n" #~ " Ole hyvä ja uudelleenkäynnistä SABnzbd toisella porttinumerolla." #~ msgid "Add new downloads" #~ msgstr "Lisää uusia latauksia" #~ msgid "Purge Failed History" #~ msgstr "Tyhjennä epäonnistuneiden historia" #~ msgid "View script output" #~ msgstr "Näytä skriptin tuloste" #~ msgid "History Size" #~ msgstr "Historian koko" #~ msgid "Show Weblogging" #~ msgstr "Näytä webloki" #~ msgid "Secondary Web Interface" #~ msgstr "Toissijainen web-käyttöliittymä" #~ msgid "Activate an alternative skin." #~ msgstr "Aktivoi toissijainen teema." #~ msgid "HTTPS Support" #~ msgstr "HTTPS-tuki" #~ msgid "Queue auto refresh interval:" #~ msgstr "Jonon automaattinen päivitysväli:" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "Jonon päivitysväli web-käyttöliittymässä(sek, 0= ei päivitä)." #~ msgid "Do not require the API key." #~ msgstr "Älä vaadi API avainta." #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "KÄYTÄ OMALLA VASTUULLA!" #~ msgid "Step One" #~ msgstr "Vaihe yksi" #~ msgid "Step Two" #~ msgstr "Vaihe kaksi" #~ msgid "Step Three" #~ msgstr "Vaihe kolme" #~ msgid "Step Four" #~ msgstr "Vaihe neljä" #~ msgid "Step Five" #~ msgstr "Vaihe viisi" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "Esim. 119 tai 563 SSL yhteyksille" #~ msgid "Please enter a whole number." #~ msgstr "Syötä kokonaisluku." #~ msgid "This field is required." #~ msgstr "Tämä kenttä on pakollinen." #~ msgid "Misc" #~ msgstr "Muut" #~ msgid "Access" #~ msgstr "Pääsy" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Aktivoi HTTPS pääsy SABnzbd-ohjelmaan." #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Tahdon, että SABnzbd on käytettävissä vain omalta PC:ltäni." #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "" #~ "Tahdon, että SABnzbd on käytettävissä jokaiselta verkossani olevalta PC:ltä." #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "Käynnistä internet selaimeni SABnzbd-sivulle kun ohjelma käynnistyy." #~ msgid "General configuration" #~ msgstr "Yleisasetukset" #~ msgid "Email Test Result" #~ msgstr "Sähköpostitestin tulokset" #~ msgid "Web server authentication" #~ msgstr "Web-palvelimen todennus" #~ msgid "QR Code" #~ msgstr "QR-koodi" #~ msgid "Folder configuration" #~ msgstr "Kansion asetukset" #~ msgid "Switches configuration" #~ msgstr "Parametrien asetukset" #~ msgid "Processing Switches" #~ msgstr "Käsittelyparametrit" #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Suojaa SABnzbd käyttö salasanalla (suositeltavaa)" #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "" #~ "Yhdistää tiedostot jotka päättyvät .001.ts,.002.ts jne. yhdeksi tiedostoksi." #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "" #~ "Yhdistää tiedostot jotka päättyvät .001,.002 jne. yhdeksi tiedostoksi." #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Huomioi yEnc CRC virheet" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Puhdistaa par tiedostot (jos varmennus/korjaus onnistui)." #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "" #~ "Jos artikkelissa on CRC virhe, yritetään hakea se toiselta palvelimelta." #~ msgid "Default Priority" #~ msgstr "Oletusprioriteetti" #~ msgid "Default Post-Processing" #~ msgstr "Oletus jälkikäsittely" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "" #~ "Käytetään kun mitään jälkikäsittelyä ei ole määriteltynä kategorialle." #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Korvaa kielletyt merkit kansionimissä" #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Korvaa kielletyt merkit kansionimissä vastaavalla merkillä (jos ei " #~ "vastaavaa, poistaa)." #~ msgid "Do not download" #~ msgstr "Älä lataa" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Käytä 12-tuntista kelloa (AM/PM)" #~ msgid "SSL type" #~ msgstr "SSL tyyppi" #~ msgid "Server configuration" #~ msgstr "Palvelinasetukset" #~ msgid "Check result of unpacking" #~ msgstr "Tarkista purkamisen lopputulos" #~ msgid "Scheduling configuration" #~ msgstr "Ajastimen asetukset" #~ msgid "Click below to test." #~ msgstr "Klikkaa alapuolelta testataksesi." #~ msgid "Remove" #~ msgstr "Poista" #~ msgid "RSS Configuration" #~ msgstr "RSS asetukset" #~ msgid "Add Feed" #~ msgstr "Lisää syöte" #~ msgid "Skip" #~ msgstr "Ohita" #~ msgid "Delete Feed" #~ msgstr "Poista syöte" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Näyttää ajat AM/PM muodossa (ei vaikuta ajastuksiin)" #~ msgid "Feeds" #~ msgstr "Syötteet" #~ msgid "Settings" #~ msgstr "Asetukset" #~ msgid "Email Options" #~ msgstr "Sähköpostiasetukset" #~ msgid "Filters" #~ msgstr "Suodattimet" #~ msgid "Email Account Settings" #~ msgstr "Sähköpostitilin asetukset" #~ msgid "Thread" #~ msgstr "Ketju" #~ msgid "Other Switches" #~ msgstr "Muut valinnat" #~ msgid "Only for optional servers" #~ msgstr "Vain valinnaisille palvelimille" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Käytä uudelleenyritysten määrää vain valinnaisille palvelimille" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Käytä V23 ellei tarjoajasi vaadi toisin!" #~ msgid "Backup server" #~ msgstr "Varapalvelin" #~ msgid "Server definition" #~ msgstr "Palvelimen tyyppi" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Jälkikäsittelyskriptien kansio" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "" #~ "Kansio jossa ovat käyttäjän skriptit joita käytetään jälkikäsittelyssä." #~ msgid "Original Foldername" #~ msgstr "Alkuperäinen kansionimi" #~ msgid "folder" #~ msgstr "kansio" #~ msgid "Hour:Min" #~ msgstr "Tunti:Min" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Lähetä: .nzb .rar .zip .gz" #~ msgid "Left" #~ msgstr "Jäljellä" #~ msgid "Pause for 12 hours" #~ msgstr "Keskeytä 12:ksi tunniksi" #~ msgid "Pause for 24 hours" #~ msgstr "Keskeytä 24:ksi tunniksi" #~ msgid "Close" #~ msgstr "Sulje" #~ msgid "Page" #~ msgstr "Sivu" #~ msgid "Are you sure you want to delete" #~ msgstr "Oletko varma, että haluat poistaa" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Ei voitu poistaa nzo:ta jälkikäsittelyn jonosta (id)" #~ msgid "User-defined categories" #~ msgstr "Käyttäjän määrittämät kategoriat" #~ msgid "Set Pause Interval" #~ msgstr "Aseta keskeytysväli" #~ msgid "Open Source URL" #~ msgstr "Avaa lähdeosoite" #~ msgid "Storage" #~ msgstr "Tallennusasema" #~ msgid "Pause Interval" #~ msgstr "Keskeytysväli" #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "Kun SABnzbd on käynnistynyt uudelleen, voit käyttää sitä seuraavasta " #~ "osoitteesta: %s" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Lue syöte hakee vain syötteen uuden sisällön. " #~ "Pakota lataus hakee kaikki vastaavat NZB:t heti." #~ msgid "New Feed URL" #~ msgstr "Uuden syötteen osoite" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Käytetään kun mitään prioriteettiä ei ole määritettynä kategorialle." #~ msgid "Defines post-processing and storage." #~ msgstr "Määrittää jälkikäsittelyn ja tallennuksen." #~ msgid "Sorting configuration" #~ msgstr "Lajittelun asetukset" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Ottaa jaksojen lajittelun ja uudelleennimeämisen käyttöön." #~ msgid "Generic Sorting" #~ msgstr "Yleinen lajittelu" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Ottaa yleisen lajittelun ja uudelleennimeämisen käyttöön." #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Ota käyttöön jos latauksia ei ole laitettu omiin kansioihinsa." #~ msgid "Plush Options" #~ msgstr "Plush asetukset" #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "" #~ "Ottaa päivämäärän mukaan nimettyjen tiedostojen lajittelun ja " #~ "uudelleennimeämisen käyttöön." #~ msgid "Enable Filejoin" #~ msgstr "Tiedostojen yhdistäminen käytössä" #~ msgid "Enable built-in unzip functionality." #~ msgstr "Ottaa käyttöön sisäänrakennetun unzip toiminnon." #~ msgid "Enable built-in unrar functionality." #~ msgstr "Ottaa käyttöön sisäänrakennetun unrar toiminnon." #~ msgid "Enable Unrar" #~ msgstr "Unrar käytössä" #~ msgid "Enable Quick Check" #~ msgstr "Pikatarkistus käytössä" #~ msgid "Enable MultiCore Par2" #~ msgstr "Moniydin Par2 käytössä" #~ msgid "Enable TS Joining" #~ msgstr "TS-tiedostojen yhdistäminen käytössä" #~ msgid "Enable Par Cleanup" #~ msgstr "Par puhdistus käytössä" #~ msgid "Used when no user script is defined by the category." #~ msgstr "" #~ "Käytetään kun mitään käyttäjän skriptiä ei ole määritettynä kategorialle." #~ msgid "Default User Script" #~ msgstr "Käyttäjän oletusskripti" #~ msgid "Notification classes" #~ msgstr "Ilmoituksien luokat" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "" #~ "Ottaa luokat käyttöön viesteille joita raportoidaan (ei mitään, yksi tai " #~ "monta)" #~ msgid "Groups / Indexer tags" #~ msgstr "Ryhmien / Indeksoijan tunnisteet" #~ msgid "Delete all failed items from History?" #~ msgstr "Poistetaanko kaikki epäonnistuneet kohteet historiasta?" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Tarkistaa purkamisen lopputulokset (täytyy olla pois päältä joissain " #~ "tiedostojärjestelmissä)." #~ msgid "Disable API-key" #~ msgstr "Poista käytöstä API avain" #~ msgid "Site API Key" #~ msgstr "Sivuston API avain" #~ msgid "Automatic Feedback" #~ msgstr "Automaattinen palaute" #~ msgid "Enable OZnzb Integration" #~ msgstr "OZnzb integraatio käytössä" #~ msgid "OZnzb" #~ msgstr "OZnzb" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "" #~ "Lähetä automaattisesti laskettu latauksen vahvistustulos indeksoijalle." #~ msgid "Refer to https://www.oznzb.com/profile" #~ msgstr "Tarkista osoitteesta https://www.oznzb.com/profile" #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Lisää enemmän toimintoja, kuten arvostelut ja lisätiedot jotka saadaan kun " #~ "yhdistetään OZnzb indeksointiin." #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Tämän avaimen avulla indeksoija tietää kuka olet. Tarkista avain osoitteesta " #~ "https://www.oznzb.com/profile." #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "VAROITUS: Keskeytetty lataus \"%s\" salatun RAR tiedoston vuoksi" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "VAROITUS: Peruutettiin lataus \"%s\" salatun RAR arkiston vuoksi" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Ohita par2 tarkistus kun tiedostot ovat 100% ladattuja." SABnzbd-2.3.2/po/main/fr.po0000644000000000000000000050021013217005051013430 0ustar 00000000000000# French translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2017-12-06 19:46+0000\n" "Last-Translator: Fred <88com88@gmail.com>\n" "Language-Team: French \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:30+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Impossible de démarrer l'interface web" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "" "Impossible de trouver le template de l'interface web : %s, nouvelle " "tentative avec le template standard" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" "SABYenc désactivé: aucune version correcte n'a été trouvée ! (v%s trouvée, " "v%s attendue)" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" "Module SABYenc... NON trouvé ! v%s attendue - https://sabnzbd.org/sabyenc" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "module _yenc... Introuvable!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "binaire par2... Introuvable!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "La vérification et la réparation ne seront pas possibles." #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "Fichier binaire MultiPar... NON trouvé !" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" "Votre version de UNRAR est %s, nous recommandons la version %s ou plus.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "Les téléchargements ne seront pas décompressés." #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "binaire unrar... Introuvable!" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "binaire unzip... Introuvable!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "Binaire 7za ... Introuvable!" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "S'il vous plaît soyez conscient que l'Hôte 0.0.0.0 aura besoin d'une adresse " "IPv6 pour les accès externes" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "Les ports HTTP et HTTPS ne peuvent pas être identiques" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" "SABnzbd a été démarré avec l'encodage %s, celui-ci devrait être UTF-8. " "Attendez-vous à des problèmes avec les noms de fichiers et de répertoires " "Unicode dans les téléchargements." #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "HTTPS désactivé car le certificat et la clé n'ont pas été trouvés" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Impossible de démarrer l'interface web : " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "Impossible d'accéder au service SABHelper" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s démarré" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Avertissement" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Erreur" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "Arrêt de SABnzbd terminé" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Le nom d'hôte n'est pas défini." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "" "Aucune connexion n'est configurée. Veuillez définir au moins une connexion." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Mot de passe masqué en ******, veuillez le ressaisir." #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Paramètres serveur incorrects" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "" "Délai dépassé : essayez d'activer SSL ou de vous connecter sur un port " "différent." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Délai dépassé" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" "Protocole SSL inconnu: essayez de désactiver SSL ou de vous connecter sur un " "autre port." #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Adresse du serveur erronée" #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Le serveur a interrompu l'ouverture de session." #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Le serveur requiert un identifiant et un mot de passe." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Connexion réussie!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Echec d'authentification, vérifiez les identifiant/mot de passe." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "Trop de connexions, veuillez mettre en pause le téléchargement ou essayer " "plus tard" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Impossible de déterminer le résultat de la connexion (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Signal %s intercepté, enregistrement et fermeture en cours..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Erreur fatale lors de l'enregistrement" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Essai de récupération du NZB depuis %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "L'enregistrement de %s a échoué" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Impossible de créer le fichier temporaire pour %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Test de l'état du serveur inexistant %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Échec dans tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Echec du chargement de %s" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Le chargement de %s a échoué avec l'erreur %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Test de Notification" #: sabnzbd/api.py msgid " Resolving address" msgstr " Résolution de l'adresse" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Aucun" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Par défaut" #: sabnzbd/api.py msgid "unknown" msgstr "inconnu" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Echec de la compilation de regex pour la recherche du terme : %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "Espace disque faible, PAUSE forcée" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Disque plein ! Pause forcée" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Erreur de disque lors de la création du fichier %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Erreur fatale dans l'assembleur" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" "ATTENTION : la tâche \"%s\" a été mise en pause à cause d'un fichier RAR " "chiffré (tous les mots de passe fournis ont été essayés)" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" "ATTENTION : la tâche \"%s\" a été abandonnée à cause d'un fichier RAR " "chiffré (tous les mots de passe fournis ont été essayés)" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Interrompu, cryptage détecté" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "AVERTISSEMENT : Le fichier RAR\"%s\" contient une extension indésirable. Le " "fichier indésirable est %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "L'extension indésirable est dans le fichier rar %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Interrompu, extension indésirable détectée" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "" "AVERTISSEMENT : Tâche \"%s\" mise en pause à cause du classement (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "AVERTISSEMENT : tâche \"%s\" annulée à cause du classement (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Tâche annulée, le filtre de classement a été vérifié (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s manquant(s)" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" "La tâche \"%s\" est probablement chiffrée en raison d'un RAR ayant le même " "nom à l'intérieur de ce RAR" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" "La tâche \"%s\" est probablement chiffrée : \"password\" dans le nom de " "fichier \"%s\"" #: sabnzbd/assembler.py msgid "video" msgstr "vidéo" #: sabnzbd/assembler.py msgid "audio" msgstr "audio" #: sabnzbd/assembler.py msgid "spam" msgstr "spam" #: sabnzbd/assembler.py msgid "passworded" msgstr "protégé par mot de passe" #: sabnzbd/assembler.py msgid "downvoted" msgstr "rejeté" #: sabnzbd/assembler.py msgid "keywords" msgstr "mots-clés" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Quota atteint, téléchargement mis en pause" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s n'est pas une adresse email valide" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Adresse du serveur requise" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Impossible de créer %s dossier %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Impossible d'écrire dans le fichier INI %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Impossible de créer le fichier de sauvegarde pour %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Encodage mot de passe incorrect %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s n'est pas une valeur octale correcte" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "Le chemin UNC \"%s\" n'est pas autorisé ici" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Erreur : la longueur du chemin doit être inférieure à %s." #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "" "Erreur : La file d'attente n'est pas vide, impossible de changer le dossier." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "" "Impossible d'écrire dans la base de données de l'historique, vérifier les " "droits d'accès !" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "" "Base de données d'historique endommagée, création d'une nouvelle base" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "Echec de la commande SQL, voir le journal" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Impossible de fermer la base de données, voir le journal" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Étape de journalisation invalide dans l'historique pour %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Échec du décodage de %s" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "Échec du décodeur : mémoire insuffisante" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Article yEnc mal construit dans %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Erreur inconnue lors du décodage de %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "UUencode détecté, seul l'encodage yEnc est compatible [%s]" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => absent de tous les serveurs, rejeté" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "Décompression Directe" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Terminé" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "%s fichier(s)/dossier(s) extrait(s) en %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "La Décompression Directe a été activée automatiquement." #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" "Les tâches seront décompréssées pendant le téléchargement pour réduire le " "temps de post-traitement. Fonctionne uniquement pour les tâches qui ne " "nécessitent aucune réparation." #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "Impossible de lire %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Erreur lors de l'ajout de %s, suppression" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Erreur lors de la suppression de %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Impossible de lire le dossier surveillé %s" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Reprise en cours" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "En pause" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Vous devez définir une bande passante maximale avant de pouvoir définir une " "limite de bande passante" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Le serveur %s sera ignoré pendant %s minutes" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Échec d'initialisation de %s@%s pour la raison suivante : %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "Trop de connexions au serveur %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Partage de compte probable" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Échec de la connexion au serveur %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Impossible de se connecter au serveur %s [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "La connexion à %s@%s a échoué, message=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Le serveur %s requiert un identifiant/mot de passe" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Erreur suspecte dans le téléchargeur" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Arrêt en cours..." #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Échec de connexion au serveur de messagerie" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "Échec de l'initialisation de la connexion TLS" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "" "Le serveur n'a pas répondu correctement au protocole d'identification " "\"hello\"" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Échec de l'authentification au serveur de messagerie" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Aucune méthode d'authentification appropriée n'a été trouvé" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "Échec d'authentification inconnu dans le serveur de messagerie" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Échec de l'envoi de l'e-mail" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Échec de la fermeture de la connexion à la messagerie" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "L'envoi de l'e-mail a réussi" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Impossible d'envoyer, données requises manquantes" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Impossible de trouver les modèles d'email dans %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Aucun destinataire déterminé, aucun email envoyé" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Codage non valide pour le modèle d'email %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Aucun modèle email trouvés" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "A : %s\n" "De : %s\n" "Date : %s\n" "Sujet : Alerte SABnzbd : disque plein\n" "\n" "Salut,\n" "\n" "SABnzbd a arrêté le téléchargement car le disque est presque plein.\n" "Merci de faire de la place avant de reprendre manuellement le téléchargement " "sous SABnzbd.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "" "Avertissement: LOCALHOST est ambigü, utilisez une adresse IP numérique." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "L' adresse du serveur \"%s:%s\" n'est pas valide." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "Utilisateur connecté à l'interface web" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "Utilisateur connecté" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Clé de session manquante" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Erreur : Clé de session requise" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Erreur : Clé de session incorrecte" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "Clé API manquante, entrez la clé API de la configuration générale dans votre " "application tierce :" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "Clé API incorrecte, utilisez la clé API de la configuration générale dans " "votre application tierce :" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Authentification manquante, entrez vos identifiant/mot de passe de la " "configuration générale dans votre application tierce :" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Essayez notre nouveau thème Glitter ! Nouveau design optimisé pour les " "ordinateurs et les appareils mobiles. Aller dans Config - > Général pour " "changer le thème." #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "Echec de la tentative de connexion de %s" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
Arrêt de SABnzbd terminé.
Veuillez attendre environ 5 " "secondes avant de cliquer sur le bouton ci-dessous.

Rafraîchir
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Flux RSS" #: sabnzbd/interface.py msgid "Daily" msgstr "Quotidien" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "Lundi" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Mardi" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Mercredi" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Jeudi" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Vendredi" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Samedi" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Dimanche" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "non" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Serveur non défini !" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Paramètre incorrect" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" "Le dossier de catégorie ne peut pas être un sous-dossier du dossier de " "téléchargement temporaire." #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Retour" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "ERREUR:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Valeur incorrecte pour %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "j" #: sabnzbd/misc.py msgid "h" msgstr "h" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Impossible de créer le dossier %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "%s dossier : %s erreur d'accès" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Échec lors de la création de (%s)" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Échec lors du déplacement de %s vers %s" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Erreur lors de la création de la clé et du certificat SSL" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" "Votre fichier de mot de passe contient plus de 30 mots de passe. Tester tous " "ces mots de passe prend beaucoup de temps. Essayez de n'y lister que les " "mots de passe utiles." #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Impossible de changer les permissions pour %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Exécution du script" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Post-traitement interrompu (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Script" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Arborescence trop profonde dans le fichier compressé [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Concaténation" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Séquence incomplète des fichiers à fusionner" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "La concaténation du fichiers %s a échoué" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Erreur \"%s\" lors de la concaténation des fichiers" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Erreur \"%s\" lors de l'exécution de file_join sur %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] %s fichiers fusionnés" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Échec de l'extraction, %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Erreur \"%s\" lors de l'extraction des fichiers RAR" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Erreur \"%s\" lors de l'exécution de rar_unpack sur %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Impossible de supprimer %s !" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Tentative d'extraction avec le mot de passe \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Échec de l'extraction, l'archive nécessite un mot de passe" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Extraction" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Décompresser" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Échec de l'extraction, %s n'a pas été trouvé" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "ERREUR : impossible de trouver \"%s\"" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Échec de l'extraction, erreur CRC" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "ERREUR : échec CRC pour \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" "La décompression a échoué, le fichier est trop volumineux pour le système de " "fichiers (FAT ?)" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" "ERREUR : le fichier est trop volumineux pour le système de fichiers (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "" "Échec de l'extraction, erreur d'écriture ou espace disque insuffisant ?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "ERREUR : erreur d'écriture (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Extraction échoué, le chemin est trop long" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "ERREUR : chemin trop long (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Échec de l'extraction, voir le journal" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "ERREUR : %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Fichier RAR inutilisable" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "Fichier RAR corrompu" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s fichiers dans %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Erreur \"%s\" lors de l'exécution de unzip() sur %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Tentative 7zip avec le mot de passe \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "" "La collection 7ZIP \"%s\" est incomplète, impossible d'extraire les fichiers" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Impossible de décompresser %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Contrôle rapide" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Réparation" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Contrôle rapide OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Réparation en cours" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "" "Echec de la vérification Par sur %s, mais QuickCheck (vérification rapide) " "réussi !" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Échec de la réparation, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Erreur %s lors de l'exécution de par2_repair sur la collection %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "" "Erreur \"%s\" lors de l'exécution de par2_repair sur la collection %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] PAR2 a reçu des paramètres incorrects, vérifiez dans Configuration-> " "Paramètres Switches" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Vérifié dans %s, tous les fichiers sont corrects" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Vérifié dans %s, réparation nécessaire" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" "Paramètres ou fichiers PAR2 non valides, impossible de vérifier ou réparer." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "Récupération de %s blocs..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Récupération en cours" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "Échec de la réparation, pas assez de blocs de réparation (manque %s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Réparation en cours" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Réparé(s) dans %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "Vérification de la réparation" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Disque plein" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Vérification en cours" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "Vérification des fichiers supplémentaires" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Vérification" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" "Le script Python \"%s\" n'est pas configuré avec les permissions d’exécution " "(+x)" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Ce serveur n'authorise pas de connexion SSL sur ce port" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" "Incompatibilité du nom d'hôte du certificat : le nom d'hôte du serveur n'est " "pas répertorié dans le certificat. Il s'agit d'un problème de serveur." #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" "Le certificat n'est pas valide. C'est probablement un problème de serveur." #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "Le serveur %s utilise un certificat peu fiable [%s]" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Démarrage/Arrêt" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "NZB ajouté" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Post-traitement démarré" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Tâche terminé" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "La tâche a échoué" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "File d'attente terminée" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Autres messages" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Non disponible" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Echec d'envoi du message Prowl" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Mauvaise réponse de Pushover (%s) : %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Échec de l'envoi du message Pushover" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Mauvaise réponse de Pusbullet (%s) : %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Échec de l'envoi du message Pushbullet" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "Le script a renvoyé le code de sortie %s et le résultat \"%s\"" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "Le script de notification \"%s\" est introuvable" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "Echec d'envoi de la notification Windows" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "" "Ancienne file d'attente détectée, utiliser Statut-> Réparation pour " "convertir la file d'attente" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Fichier de file d'attente incompatible, impossible de continuer" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Erreur lors du chargement de %s, fichier corrompu détecté" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "Impossible de redémarrer NZB après la pré-vérification (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB ajouté à la file d'attente" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Encodage inconnu" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Fichier %s vide, ignoré" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Echec de l'importation des fichiers %s depuis %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Fichier NZB %s incomplet" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Fichier NZB invalide %s, ignoré (raison=%s, ligne=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Fichier NZB %s vide" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "Le script de pré-file d'attente a marqué la tâche comme échouée" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Doublon NZB ignoré \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "Échec de duplication du NZB \"%s\"" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "Dupliquer NZB" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Mise en pause du doublon NZB \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Interrompu, ne peut être achevé" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "DOUBLON" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "CHIFFRÉ" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "TROP VOLUMINEUX" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "INCOMPLET" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "INDÉSIRABLE" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "FILTRÉ" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "PATIENTER %s sec" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "PROPAGATION %s min" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Téléchargé en %s à %sB/s de moyenne" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Âge" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s articles malformés" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s articles manquants" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s articles avec doublons sans correspondance" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s articles ont été retirés" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Erreur lors de l'importation de %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Avertissements" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "A l'arrêt" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Configuration" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "File d'attente" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Vider la file d'attente" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Historique" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Vider l'historique" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Limiter la vitesse" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Mettre en pause" #: sabnzbd/osxmenu.py msgid "min." msgstr "min." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Reprendre" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Analyser le dossier surveillé" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Lire tous les flux RSS" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Dossier complet" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Dossier incomplet" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Résoudre les problèmes" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Redémarrer" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Redémarrer sans se connecter" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Quitter" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Mettre en file d'attente les 10 premiers articles" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Vide" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Historique des 10 derniers articles" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Nouvelle version disponible" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Aller à l'assistant" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Arrêt en cours..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Problème avec" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd a besoin d'un port tcp/ip libre pour le serveur Web " "interne.
\n" " La plage de ports %s à %s a été essayée mais elle n'est pas " "disponible.
\n" " Un autre logiciel utilise ce port ou SABnzbd est déjà en cours " "d'exécution.
\n" "
\n" " Veuillez redémarrer SABnzbd avec un port différent." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "" "Si vous obtenez ce message d'erreur à nouveau, veuillez essayer un nombre " "différent.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd a besoin d'une adresse hôte valide pour son serveur Web " "interne.
\n" " Vous avez spécifié une adresse non valide.
\n" " Les valeurs sûres sont localhost et 0.0.0.0
\n" "
\n" " Veuillez redémarrer SABnzbd avec une adresse hôte correcte." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd a détecté des données sauvegardées avec une autre version de " "SABnzbd
\n" " mais ne peut réutiliser les données de l'autre programme.

\n" " Vous voudrez peut-être terminer votre première file d'attente avec " "l'autre programme.

\n" " Après cela, lancez ce programme avec l'option \"--clean\".
\n" " Cette opération effacera la file d'attente actuelle et l'historique " "!
\n" " SABnzbd a lu le fichier \"%s\"." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd ne peut pas trouver ses fichiers d'interface web dans %s.
\n" " Veuillez réinstaller le programme.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd a détecté une erreur fatale :" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd a détecté que le fichier sqlite3.dll est manquant.

\n" " Certains antivirus mal conçu peuvent supprimer ce fichier.
\n" " S'il vous plaît vérifier votre antivirus, essayez de ré-installer " "SABnzbd et plaignez vous à l'éditeur de l'antivirus.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Appuyez sur la touche Drapeau+R et tapez la ligne (exemple) :" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Ouvrez une fenêtre de Terminal et tapez la ligne (exemple) :" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Le programme n'a pas démarré !" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" "Impossible de lier le port %s sur %s. Un autre logiciel utilise le port ou " "SABnzbd est déjà en cours d'exécution." #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Erreur fatale" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "Impossible de lancer le navigateur web, probablement pas trouvé" #: sabnzbd/panic.py msgid "Access denied" msgstr "Accès refusé" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "" "Erreur %s: vous devez fournir un nom d'utilisateur et un mot de passe valide." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" "Le système de fichiers du dossier de téléchargements terminés %s est au " "format FAT, limitant la taille maximale d'un fichier à 4 Go" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" "Le module subprocessww est manquant. Attendez-vous à des problèmes avec les " "noms de fichiers et de répertoires Unicode dans les téléchargements." #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "" "Le téléchargement pourrait échouer, seulement %s des %s requis sont " "disponibles" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Le téléchargement a échoué - absent de vos serveur(s)" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Pas de post-traitement car la vérification a echoué" #: sabnzbd/postproc.py msgid "Moving" msgstr "Déplacement" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "%s envoyé dans la file d'attente" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Erreur lors du renommage de \"%s\" en \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Impossible de déplacer les fichiers" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Exécution du script utilisateur %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "%s exécuté" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Le code script de sortie est %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Plus" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Échec du post-traitement pour %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "voir le journal" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Échec du téléchargement" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Échec du nettoyage de %s." #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Erreur lors de la suppression du dossier de travail (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Téléchargement terminé" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Impossible de créer le dossier final %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Post-traitement" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Pas de fichiers par2" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Essai vérification SFV" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Certains fichiers n'ont pas pu être vérifiés \"%s\"" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Vérifié avec succès en utilisant des fichiers SFV" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "Tentative de vérification RAR" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "[%s] La vérification RAR a échoué: %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "Protégé par un mot de passe" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "Fichiers RAR vérifiés avec succès" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "Echec lors de la vérification des fichiers RAR" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Échec de la suppression de %s" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Échec de la mise en hibernatation" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Échec de la mise en veille" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Erreur lors de l'arrêt du système" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "id de l'Indexer (%s) non trouvé pour le fichier des classements" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Adresse du serveur" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "Clé API" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" "Cette clé fournit l'identité à l'indexeur. Vérifiez votre profil sur le site " "web de l'indexeur." #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Description du flux RSS incorrecte \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Échec de la récupération RSS de %s : %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Vous n'avez pas d'authentification valide pour ce flux %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "" "Erreur du côté serveur (code serveur %s) ; n'a pas pu obtenir %s sur %s" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "" "Le serveur %s utilise un certificat de sécurité HTTPS non authentifié" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "Le flux RSS %s était vide" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Flux incompatible" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Entrée vide de flux RSS trouvée (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Afficher l’interface" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Ouvrir le dossier des complets" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Arrêter" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Restant" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Ajouter NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Mauvaise planification %s à %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Action inconnue : %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Planification pour un serveur non existant %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Télécharger" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Concaténer" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Source" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Serveurs" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Échec" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Échoué" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "En attente" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Réparation en cours..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Décompression en cours..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Déplacement en cours..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Exécution de script en cours..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Récupération des blocs supplémentaires ..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Vérification rapide..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Vérification..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Téléchargement" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "Délai de propagation" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Fréquence" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Action" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Arguments" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Tâche" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "désactiver le serveur" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "activer le serveur" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Limite de vitesse" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Suspendre tout" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Mettre en pause le post-traitement" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Reprendre le post-traitement" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Lire les flux RSS" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Retirer les tâches échouées" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Effacer les tâches terminées" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Mettre en pause les tâches de priorité faible" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Mettre en pause les tâches de priorité normale" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Mettre en pause les tâches de priorité haute" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Reprendre les tâches de priorité faible" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Reprendre les tâches de priorité normale" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Reprendre les tâches de priorité haute" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Activer la gestion de quota" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Désactiver la gestion de quota" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "Mettre en pause les tâches ayant une catégorie" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "Reprendre les tâches ayant une catégorie" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Désactivé" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Très basse" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Modéré" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normale" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Haute" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Urgence" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Basse" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "Mo" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "Go" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "heure" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "heures" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "min" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "mins" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "sec" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "secondes" #: sabnzbd/skintext.py msgid "day" msgstr "jour" #: sabnzbd/skintext.py msgid "days" msgstr "jours" #: sabnzbd/skintext.py msgid "week" msgstr "semaine" #: sabnzbd/skintext.py msgid "Month" msgstr "Mois" #: sabnzbd/skintext.py msgid "Year" msgstr "Année" #: sabnzbd/skintext.py msgid "January" msgstr "Janvier" #: sabnzbd/skintext.py msgid "February" msgstr "Février" #: sabnzbd/skintext.py msgid "March" msgstr "Mars" #: sabnzbd/skintext.py msgid "April" msgstr "Avril" #: sabnzbd/skintext.py msgid "May" msgstr "Mai" #: sabnzbd/skintext.py msgid "June" msgstr "Juin" #: sabnzbd/skintext.py msgid "July" msgstr "Juillet" #: sabnzbd/skintext.py msgid "August" msgstr "Août" #: sabnzbd/skintext.py msgid "September" msgstr "Septembre" #: sabnzbd/skintext.py msgid "October" msgstr "Octobre" #: sabnzbd/skintext.py msgid "November" msgstr "Novembre" #: sabnzbd/skintext.py msgid "December" msgstr "Décembre" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Jour du mois" #: sabnzbd/skintext.py msgid "This week" msgstr "Cette semaine" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Ce mois" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "Aujourd'hui" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Total" #: sabnzbd/skintext.py msgid "on" msgstr "oui" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Paramètres" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Version de Python" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Page d'accueil" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "ou" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Hôte" #: sabnzbd/skintext.py msgid "Comment" msgstr "Commentaire" #: sabnzbd/skintext.py msgid "Send" msgstr "Envoyer" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Annuler" #: sabnzbd/skintext.py msgid "Other" msgstr "Autre" #: sabnzbd/skintext.py msgid "Report" msgstr "Signaler" #: sabnzbd/skintext.py msgid "Video" msgstr "Vidéo" #: sabnzbd/skintext.py msgid "Audio" msgstr "Audio" #: sabnzbd/skintext.py msgid "Not used" msgstr "Non utilisé" #: sabnzbd/skintext.py msgid "or less" msgstr "ou moins" #: sabnzbd/skintext.py msgid "Log in" msgstr "Se connecter" #: sabnzbd/skintext.py msgid "Log out" msgstr "Se déconnecter" #: sabnzbd/skintext.py msgid "Remember me" msgstr "Se souvenir de moi" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "L'outil de téléchargement usenet automatique" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Enregistrer" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Êtes-vous sûr ?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Supprimer tous les fichiers téléchargés ?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Accueil" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Configuration" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Statut" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Aide" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Forum" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "Incidents" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "Soutenez le projet, faites un don !" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Général" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Répertoires" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Switches" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Planification" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Notifications" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "Email" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Catégories" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Triage" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Spécial" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Rechercher" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Dossier de téléchargement" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "EN PAUSE" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "%s articles mis en cache (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Sysload" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Une nouvelle version %s est disponible" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Etes-vous sûr de vouloir arrêter SABnzbd ?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Ajouter" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Ajouter un fichier" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Catégorie" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Traitement en cours" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Priorité" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Réparer" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Décompresser" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Supprimer" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "D" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "S" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Forcer" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Arrêter" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "Saisir une URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "En fin de file d'attente" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Éteindre le PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "Mettre le PC en veille" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Mettre le PC en hibernation" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Arrêter SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Vitesse limite" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Pause de" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Ordre" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Nom" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "TRE" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "ÂGE" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Suppr." #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Réessayer" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Actions" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Scripts" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Supprimer tous les éléments de la file d'attente ?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Vider les NZB" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Purger les NZB & supprimer les fichiers" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Réessayez toutes les tâches échouées" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Supprimer NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Supprimer le NZB & supprimer les fichiers" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "de" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Articles manquants" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Quota restant" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "manuel" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Réinitialiser le quota maintenant" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Supprimer tous les éléments terminés de l'historique ?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Masquer les détails" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Afficher les détails" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Afficher les échoués" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Afficher Tout" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Taille" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Purger les NZB échoués" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Purger les NZBs échoués & supprimer les fichiers" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Vider les NZB terminés" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "Purger les NZBs de la page en cours" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "NZB supplémentaire optionnel" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Chemin d'accès" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Relancer toutes les tâches échouéés" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Réessayer tous" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus/spam" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "En dehors du délai de rétention" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Autre problème" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Forcer la déconnexion" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Ceci enverra un email de test sur votre compte." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Afficher le journal" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Email de test" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Journalisation" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Erreurs/Avertissements" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ Info" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ Debug" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Connections" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Avertissements récents" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "éffacer" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Débloquer" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Identifiant de l'article" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Collection de fichiers" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Quand" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Type" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Activé" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Tableau de bord" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Echec de connexion !" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Adresse IPv4 locale" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Adresse IPv4 publique" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "Adresse IPv6" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Nameserver / DNS Lookup" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "Modèle de CPU" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "Performance du système ( Pystone )" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Vitesse du dossier \"Download\"" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Vitesse du dossier \"Complete\"" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Vitesse d'écriture" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "" "Impossible d'écrire. Vérifiez que le répertoire est accessible en écriture." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Cliquez sur le bouton de test \"Répéter\" ci-dessous pour déterminer" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Refaire le test" #: sabnzbd/skintext.py msgid "Config File" msgstr "Fichier de configuration" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Cache utilisé" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Ceci redémarrera SABnzbd.
\r\n" "Utilisez cette fonction si vous pensez avoir un problème de stabilité.
\r\n" "Les téléchargements en cours seront mis en pause puis repris." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" "
Si l'authentification est activée, vous devrez vous identifier à " "nouveau." #: sabnzbd/skintext.py msgid "Advanced" msgstr "Options avancées" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Il y a des dossiers orphelins dans le répertoire de téléchargement.
Vous pouvez choisir de les supprimer (y compris les fichiers) ou de les " "renvoyer dans la file d'attente." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "Ceci redémarre SABnzbd et fait une complète reconstruction
de la file " "d'attente, tout en conservant les fichiers déjà téléchargés.
Ceci " "modifiera l'ordre de la file d'attente." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Les modifications n'ont pas été enregistrées et seront perdues." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" "La session expirera quand votre adresse IP changera ou quand SABnzbd sera " "redémarré." #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Activer Unzip" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "Activer 7zip" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "Par2 multi-cœur" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" "Les connexions sécurisées (SSL) de SABnzbd vers les serveurs Usenet et aux " "sites HTTPS seront chiffrées, mais la validation de l'identité d'un serveur " "à l'aide de ses certificats n'est pas possible. Python 2.7.9 ou supérieur, " "OpenSSL 1.0.2 ou supérieur, et des certificats locaux AC à jour sont requis." #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" "Accélérez les réparations en installant Par2 multi-coeur, disponible sous de " "nombreuses plateformes." #: sabnzbd/skintext.py msgid "Version" msgstr "Version" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Temps de fonctionnement" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Secours" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Consultez le Wiki pour plus d'info à ce sujet (en anglais) !" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Redémarrage de SABnzbd en cours..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Les modifications nécessiteront un redémarrage de SABnzbd!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "Serveur web SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "Hôte SABnzbd" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Hôte sur lequel SABnzbd doit attendre les connexions." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "Port SABnzbd" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Port que SABnzbd doit surveiller." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Interface Web" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Choisissez un thème." #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "Identifiant SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Nom d'utilisateur pour l'authentification (facultatif)." #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "Mot de passe SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Mot de passe pour l'authentification (facultatif)." #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" "Vos paramètres actuels permettent un accès externe complet à l'interface " "SABnzbd si l'hôte ou le port SABnzbd est ouvert vers l'internet." #: sabnzbd/skintext.py msgid "Security" msgstr "Sécurité" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "Activer HTTPS" #: sabnzbd/skintext.py msgid "not installed" msgstr "non installé" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Active l'accès à l'interface via une adresse HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "Port HTTPS" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Si vide, le port standard écoutera seulement le HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "Certificat HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Nom du fichier ou chemin du certificat HTTPS." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" "Générer à nouveau les certificat et clé auto-signés. Nécessite le " "redémarrage de SABnzbd !" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "Clé HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Nom du fichier ou chemin de la clé HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "Certificats de chaîne HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Nom du fichier ou chemin d'accès de la chaîne HTTPS." #: sabnzbd/skintext.py msgid "Tuning" msgstr "Réglages" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "Invervalle de vérification RSS" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Intervalle de vérification (en minutes, au moins 15). Inactif quand vous " "utilisez le Planificateur !" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Vitesse maximale de la ligne" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Pourcentage de la vitesse de la ligne" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "" "Quel est le pourcentage de la vitesse de la ligne que SABnzbd doive " "utiliser, par exemple 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Limite du cache d'articles" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Mettre les articles en cache pour réduire les accès disque.
En " "Octets, peut être suivi de K,M,G. Par exemple : \"64M\" ou \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Nettoyer la liste" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Liste des extensions de fichiers qui doivent être supprimés après le " "téléchargement.
nfo
ou nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "Conservation de l'historique" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" "Supprimer automatiquement les tâches terminées de l'historique. Attention, " "la Détection des Doublons et certains outils externes s'appuient sur les " "informations de l'historique." #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "Conserver toutes les tâches" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "Nombre maximum de tâches complétées historisées" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "Durée maximale d'historisation des tâches complétées" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "Ne conserver aucune tâche terminée" #: sabnzbd/skintext.py msgid "Jobs" msgstr "Tâches" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Enregistrer les modifications" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "Rétablir les valeurs par défaut" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Réinitialiser" #: sabnzbd/skintext.py msgid "Language" msgstr "Langue" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Choisir la langue de l'interface web." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" "Aidez-nous à traduire SABnzbd dans votre langue !
Améliorez les " "traductions existantes ou ajoutez celles qui manquent ici :" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "" "Cette clé permettra aux programmes tiers d'avoir un accès complet à SABnzbd." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "Clé NZB" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "Cette clé permettra aux programmes tiers de pouvoir ajouter des NZB à " "SABnzbd." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Générer une nouvelle clé" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "Clé API code QR" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Liste des plages de réseau local" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Toutes les adresses de réseau local commencent par ces préfixes (souvent " "\"192.168.1.\" )" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Accès Internet externe" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" "Vous pouvez définir les droits d'accès pour les systèmes en dehors de votre " "réseau local. Requiert la liste des plages de réseaux locaux à définir." #: sabnzbd/skintext.py msgid "No access" msgstr "Aucun accès" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Ajouter des fichiers NZB " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (aucune configuration)" #: sabnzbd/skintext.py msgid "Full API" msgstr "API complète" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Interface Web complète" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "Seul l'accès extérieur nécessite un identifiant" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "NOTE: Les dossiers seront créés automatiquement lors de " "l'enregistrement. Il est possible d'utiliser des chemins absolus pour " "sauvegarder en dehors du répertoire par défaut." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Dossiers utilisateur" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Parcourir" #: sabnzbd/skintext.py msgid "In" msgstr "Dans" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Dossier temporaire de téléchargement" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Emplacement de stockage des téléchargements non-traités.
Modifiable " "uniquement si la file d'attente est vide." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Espace disque minimum pour le dossier de téléchargement temporaire" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Mettre en pause lorsque l'espace libre est en-dessous de cette valeur.
En octets, peut être suivi de O,M,G,T. Par exemple : \"800M\" ou " "\"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Dossier de téléchargements terminés" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Emplacement des téléchargements terminés et post-traités.
Peut être " "outrepassé par les catégories définies par l'utilisateur." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Permissions pour le dossier de téléchargements terminés" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Appliquer ce modèle de permissions aux fichiers/dossiers téléchargés.
En notation octale. Par exemple : \"755\" ou \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Dossier à surveiller" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Dossier d'import automatique des fichiers .nzb.
Prends en compte " "également les nzb contenus dans les fichiers .zip, .rar et .tar.gz." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Intervalle de scan" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "" "Nombre de secondes entre chaque scan du dossier pour vérifier la présence de " "fichiers .nzb." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "Dossier des scripts" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "Dossier contenant les scripts utilisateurs." #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Dossier des modèles d'email" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Dossier contenant les modèles d'email définis par l'utilisateur." #: sabnzbd/skintext.py msgid "Password file" msgstr "Fichier de mot de passe" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Le fichier contenant tous les mots de passe sera testé sur les fichiers RAR " "chiffrés." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Dossiers système" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Dossier administrateur" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Emplacement de la file d'attente et de la base de données d'historique.
Ne peut être changé que lorsque la file d'attente est vide." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "Les données ne seront pas déplacées. Requiert un redémarrage de " "SABnzbd !" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Dossier du fichier journal" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Emplacement des fichiers journaux de SABnzbd.
Redémarrage requis " "!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr "Dossier de sauvegarde des fichiers .nzb" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Emplacement où les fichier .nzb seront archivés." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Dossier racine par défaut" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Télécharger tous les fichiers par2" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" "Ceci évite les réparations multiples en téléchargeant tous les fichiers par2 " "nécessaires." #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Activer l'extraction récursive" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Décompresser les archives (rar, zip, 7z) à l'intérieur des archives." #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Ignorer tous les dossiers à l'intérieur des archives" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Tous les fichiers iront dans un seul dossier." #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Télécharger uniquement les articles en tête de file d'attente" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Activer pour moins d'utilisation de la RAM. Désactiver pour éviter que les " "téléchargements lents bloquent la file d'attente." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Ne post-traiter que les tâches vérifiées" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "" "Limite le post-traitement aux tâches qui ont passé avec succès toutes les " "vérifications PAR2." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Action quand un RAR chiffré est téléchargé" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "En cas de \"Pause\", vous devrez mettre un mot de passe pour reprendre la " "tâche." #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Détecter les doublons de téléchargement" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" "Détecter les fichiers NZB identiques (en fonction des éléments de votre " "historique ou des fichiers .nzb du dossier de backup)" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Détecter les doublons d'épisodes de séries" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" "Détecter les épisodes de série identiques (en fonction du modèle " "\"nom/saison/épisode\" des éléments de votre historique)" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "Autoriser les versions corrigées (proper)" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" "Contourner la détection des doublons si PROPER, REAL ou REPACK est détecté " "dans l'intitulé du téléchargement" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Rejeter" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "Faire échouer la tâche (déplacer vers l'historique)" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "Taguer la tâche" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Annuler" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Action si une extension indésirable est détecté" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "" "Action si une extension indésirable est détecté dans les fichiers RAR" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Extensions indésirables" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Afficher toutes les extensions indésirables. Par exemple : exe or " "exe, com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Activer les contrôles SFV" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Fait une vérification supplémentaire basée sur les fichiers SFV." #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Le script utilisateur peut signaler la tâche comme échouée" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Lorsque le script de l'utilisateur renvoie un code de sortie \"non-zéro\", " "la tâche sera signalée comme échouée." #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "En cas d'échec, essayer avec un NZB alternatif" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "" "Certains serveurs proposent un NZB alternatif lorsqu'un téléchargement " "échoue." #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "Utiliser les tags de l'indexeur" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" "Lors du tri, utiliser les tags de l'indexeur pour le titre, la saison, " "l'episode, etc. Sinon, toutes les dénominations seront dérivées du fichier " "NZB." #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Activer le renommage du dossier" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Utiliser des noms temporaires pendant le post-traitement. Désactiver lorsque " "votre système ne le gère pas correctement." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Script utilisateur de pré-file d'attente" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Utilisé avant qu'un NZB n'entre dans la file d'attente." #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Paramètres PAR2 supplémentaires" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Paramètres 'Nice'" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "Paramètres 'IONice'" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Se déconnecter lorsque la file d'attente est vide" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "" "Se déconnecter du serveur(s) Usenet lorsque la file d'attente est vide ou en " "pause" #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Trier par âge" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Trier automatiquement les fichiers par âge (moyen)." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" "Les publications seront mises en pause jusqu'à ce qu'elles aient au moins " "cet âge. La tâche commence immédiatement si elle est passée en priorité " "Forcée." #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Vérifier les mises à jour" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Vérifier chaque semaine les mises à jour de SABnzbd." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "Versions de test également" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Remplacer les espaces dans les noms de dossier" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "" "Remplace les espaces par des underscores ( _ ) dans les noms de dossiers." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Remplacer les points dans les noms de dossier" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Remplace les points par des espaces dans les noms de dossier" #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Rendre Windows compatible" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "" "Pour les serveurs : assurez-vous que les noms soient compatibles avec " "Windows." #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Lancer le navigateur web au démarrage" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Lance le navigateur web par défaut au démarrage de SABnzbd." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Mettre en pause les téléchargements lors du post-traitement" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Met en pause les téléchargements au début du post-traitement et les reprend " "à la fin." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Ignorer les échantillons (Samples)" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Exclure les fichiers échantillons (par ex. les samples vidéo)." #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Supprimer après téléchargement" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "Vérification du certificat HTTPS" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" "Vérifier les certificats lors de la connexion aux indexeurs et sources RSS " "utilisant HTTPS." #: sabnzbd/skintext.py msgid "Server" msgstr "Serveur" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Post-traitement" #: sabnzbd/skintext.py msgid "Naming" msgstr "Appellation" #: sabnzbd/skintext.py msgid "Quota" msgstr "Quota" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indexation" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Combien peut-être télécharger ce mois (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Jour de RAZ" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "A quel jour du mois ou de la semaine (1=lundi) votre fournisseur " "réinitialise le quota ? (Optionnel avec hh:mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Reprise auto" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "" "Le téléchargement devrait-il reprendre après que le quota soit réinitialisé ?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Période du quota" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "Est-ce que le quota se réinitialise chaque jour, semaine ou mois ?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Vérifiez avant de télécharger" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Tente de prédire la réussite de la tâche avant le téléchargement complet " "(plus lent !)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "Chiffrements SSL" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "Augmenter les performances en forçant un cryptage SSL plus faible." #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Nombre de tentatives maximum" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Nombre maximal de tentatives par serveur" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Interrompre les tâches qui ne peuvent être terminées" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "S'il apparait clairement pendant le téléchargement qu'il manque trop de " "données, annuler la tâche" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "Activer l'intégration de l'indexeur" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" "Les indexeurs peuvent fournir des informations de notation lorsqu'une tâche " "est ajoutée, et SABnzbd peut signaler à l'indexeur si une tâche n'a pas pu " "être terminée." #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Activer le filtrage" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Activer les téléchargements selon les règles de filtrage." #: sabnzbd/skintext.py msgid "Abort If" msgstr "Abandonner si" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Sinon, mettre en pause si" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Classement vidéo" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Classement audio" #: sabnzbd/skintext.py msgid "Spam" msgstr "Spam" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Confirmé" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Plus de mauvais votes que de bons" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Mots-clés titre" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Liste séparée par des virgules" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Equilibrage de charge du serveur" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Empêcher l'équilibrage de charge" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Autoriser l'équilibrage de charge" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Autoriser l'équilibrage de charge avec l'optimisation pour IPv6" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "Utile si un serveur de news a plus d'une adresse IPv4/IPv6" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Ajouter un serveur" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Description du serveur" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Port" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Nom d'utilisateur" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Mot de passe" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Délai d'expiration" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Délai de rétention" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "Connexion sécurisée au serveur" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "Vérification du certificat" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" "Minimal: lorsque SSL est activé, vérifier l'identité du serveur à l'aide de " "ses certificats. Strict: vérifier et imposer le nom d'hôte correspondant." #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Désactivé" #: sabnzbd/skintext.py msgid "Minimal" msgstr "Minimal" #: sabnzbd/skintext.py msgid "Strict" msgstr "Strict" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 est la priorité la plus élevée, 100 est la priorité la plus faible" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Optionnel" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" "Pour les serveurs non fiables, sera ignorée plus longtemps en cas de " "défaillances" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Activer" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Supprimer le serveur" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Tester le serveur" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "RAZ des compteurs" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Test des détails du serveur en cours..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Bande passante" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Envoyer 'Group'" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Envoyer la commande 'group' avant la demande des articles." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Utilisez uniquement ce serveur pour ces catégories." #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" "Aucun des serveurs activés n'a la catégorie \"Par défaut\" sélectionnée. Les " "tâches de la file d'attente qui ne sont pas affectées à une des catégories " "de serveur ne seront pas téléchargées." #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Notes personnelles" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Ajouter une planification" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Planifications actuelles" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "La case à cocher à coté du nom du flux doit être cochée pour que le flux " "soit activé et qu'il soit pris en compte dans la vérification des nouveaux " "téléchargements.
Quant un flux est ajouté, seuls les nouveaux " "téléchargements seront pris en compte à moins de cliquer sur \"Forcer " "téléchargements\"." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "Séparez les URL multiples par une virgule" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Lire le flux RSS" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Forcer le téléchargement" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Filtre" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Accepter" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Rejeter" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Obligatoire" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "CatObligatoire" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Au moins" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Au plus" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "Depuis SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "À partir de la Série SxxEyy" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Correspond" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Ne correspond pas" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Téléchargé" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Lire tous les flux maintenant" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "Notification par email lorsque des téléchargements sont terminés" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Jamais" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Toujours" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Erreurs uniquement" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Notifications de disque dur plein" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "" "Envoie un email lorsque le disque dur est plein et que SABnzbd a été mis en " "pause." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Envoyer les notifications RSS" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "" "Envoie un email quand un flux RSS ajoute un fichier dans la file d'attente." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "Serveur SMTP" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Entrez le serveur de courrier sortant de votre FAI." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "Email du destinataire" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "Adresse email à laquelle seront envoyées les notifications." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "Email de l'expéditeur" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Qui doit-on indiquer comme expéditeur de l'email ?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "Identifiant (facultatif)" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Identifiant du compte pour les envois authentifiés." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "Mot de passe du compte (facultatif)" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Mot de passe du compte pour les envois authentifiés." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Activer Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Envoie les notifications à Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Utiliser seulement pour le serveur Growl à distance (hôte:port)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Mot de passe du serveur" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Mot de passe optionnel pour le serveur Growl" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "Activer NotifyOSD" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Envoie les notifications à NotifyOSD" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Centre de notification" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Envoyer des notifications au centre de notification" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Activer les notifications Windows" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Notifications Windows" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Activer les notifications Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Nécessite un compte Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "Clé API pour Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Clé API personnelle pour Prowl (obligatoire)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Activer les notifications Pushover" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Nécessite un compte Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Jeton (token) d'application" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Jeton (token) d'application (obligatoire)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Clé de l'utilisateur" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Clé de l'utilisateur (obligatoire)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Appareil(s)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Appareil(s) auxquels doivent être envoyés les messages" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "Nouvelle tentative d'urgence" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "À quelle fréquence la même notification sera envoyée (en secondes)" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "Expiration d'urgence" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" "Tenter à nouveau votre notification pendant combien de temps (en secondes)" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Activer les notifications Pushbullet" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Nécessite un compte Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Clé API personnelle" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Votre clé API Pushbullet personnelle (obligatoire )" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Appareil" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Appareil sur lequel le message doit être envoyé" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "Script de notification" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "Activer le script de notification" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "Exécute un script personnalisé" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "Quel script devons-nous utiliser pour les notifications ?" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" "Les indexeurs peuvent fournir une catégorie à l'intérieur du NZB que SABnzbd " "tentera de faire correspondre aux catégories définies ci-dessous. En outre, " "vous pouvez ajouter des termes à \"Catégories de l'indexeur / Groupes\" pour " "faire correspondre plus de catégories. Utilisez des virgules pour séparer " "les termes. Les caractères génériques sont pris en charge.
Plus " "d'informations peuvent être trouvées sur le Wiki." #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Terminer le chemin avec une étoile * empêche la création des dossiers de la " "tâche." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Les chemins relatifs des dossiers sont basés sur" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Dossier/Chemin" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "Catégories de l'indexeur / Groupes" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Tri des séries" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Activer le tri TV" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Modèle de clé" #: sabnzbd/skintext.py msgid "Clear" msgstr "Effacer" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "Appliquer les filtres" #: sabnzbd/skintext.py msgid "Presets" msgstr "Modèles prédéfinis" #: sabnzbd/skintext.py msgid "Example" msgstr "Exemple" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "Tri des films" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Activer le tri des films" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "" "Conserver les téléchargements disséminés dans des dossiers supplémentaires" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Catégories affectées" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Signification" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Modèle" #: sabnzbd/skintext.py msgid "Result" msgstr "Résultat" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Dossier Saison" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Dossier Saison" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Dossier Épisode" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Dossier Épisode" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "Nom de la tâche en tant que nom de fichier" #: sabnzbd/skintext.py msgid "Title" msgstr "Titre" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Nom du film" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Nom.Film" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Nom_Film" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Nom de la série" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Nom.Série" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Nom_Série" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Numéro de la saison" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Numéro de l'épisode" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Nom de l'épisode" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Nom.Épisode" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Nom_Épisode" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Extension du fichier" #: sabnzbd/skintext.py msgid "Extension" msgstr "Extension" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Numéro de bloc" #: sabnzbd/skintext.py msgid "Decade" msgstr "Décennie" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Nom de fichier originel" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "Nom d'origine de la tâche" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Minuscule" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEXTE" #: sabnzbd/skintext.py msgid "text" msgstr "texte" #: sabnzbd/skintext.py msgid "file" msgstr "fichier" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Chaîne de caractères de tri" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Étiquette multi-bloc" #: sabnzbd/skintext.py msgid "In folders" msgstr "Dans les dossiers" #: sabnzbd/skintext.py msgid "No folders" msgstr "Pas de dossiers" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Tri par date" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Activer le tri par date" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Dossier du nom de série" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "Dossiers Année-Mois" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Dossiers Quotidiens" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "Lettre Capitale" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Résultat traité" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Options rarement utilisées. Pour leur sens et leur explication, cliquez sur " "le bouton Aide pour accéder à la page Wiki.
Ne pas les modifier sans " "consulter le wiki en premier, car certaines ont de graves effets " "secondaires.
Les valeurs par défaut sont indiquées entre parenthèses." #: sabnzbd/skintext.py msgid "Values" msgstr "Valeurs" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Éditer les détails du NZB" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Supprimer" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Tout en haut" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Monter" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Descendre" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Tout en bas" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Tous" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Inverser" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Nom de fichier" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Sujet" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Sélection" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Mettre en pause pendant 5 minutes" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Mettre en pause pendant 15 minutes" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Mettre en pause pendant 30 minutes" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Mettre en pause pendant 1 heure" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Mettre en pause pendant 3 heures" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Mettre en pause pendant 6 heures" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "restant" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Espace libre" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Dossier temporaire" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Multi-Operations" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Maintenez la touche Maj pour sélectionner une plage" #: sabnzbd/skintext.py msgid "Check all" msgstr "Tout sélectionner" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Redémarrer SABnzbd" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Options de statut et d'interface" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Ou glissez-déposez des fichiers sur la fenêtre!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Connexion à SABnzbd perdue..." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "" "En cas de redémarrage de SABnzbd cet écran disparaîtra automatiquement!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "AVERTISSEMENT :" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Charger" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Taux de rafraîchissement" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Utiliser les paramètres globaux de l'interface" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Limite des éléments de la file d'attente" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Limite des éléments historisés" #: sabnzbd/skintext.py msgid "Date format" msgstr "Format de la date" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Colonne de file d'attente supplémentaire" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "Colonne d'historique additionnelle" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "page" #: sabnzbd/skintext.py msgid "Loading" msgstr "Chargement" #: sabnzbd/skintext.py msgid "articles" msgstr "articles" #: sabnzbd/skintext.py msgid "Rename" msgstr "Renommer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Réparer la file d'attente" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Afficher les connexions actives" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Tâches orphelines" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Renvoyer dans la file d'attente" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Tout supprimer" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Réessayer tous" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Importer le NZB depuis l'URL" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "Uploader le NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Vous pouvez également indiquer un nom de fichier" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Formats : .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Soumettre" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Ouvrir URL Info." #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Soumis. Merci !" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Pas de sélection!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Supprimer tous les fichiers sélectionnés" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Afficher/masquer les fichiers terminés" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Afficher le journal des scripts" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Mise à Jour disponible!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" "Le stockage des données locales (cookies) est désactivé dans votre " "navigateur, les réglages de l'interface seront perdus lorsque vous fermerez " "votre navigateur !" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "" "Glitter a des (nouvelles) fonctionnalités que vous devriez apprécier !" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Personnalisé" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "Affichage compact" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "Mise en page par onglets
(file d'attente et historique séparés)" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Vitesse" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Confirmer les suppressions de la file d'attente" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Confirmer les suppressions de l'historique" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Combien de temps ou jusqu'à quand souhaitez-vous mettre en pause ?" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Désolé, nous n'avons pas pu interpréter ça. Essayez encore." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Mettre en pause pour…" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Rafraîchir" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" "Tous les noms d'utilisateur, mots de passe et clés API sont automatiquement " "supprimés du journal et de la copie de vos réglages." #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Trier par Age Moins récent→Plus récent" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Trier par âge Plus récent→Moins récent" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Trier par nom A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Trier par nom Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Trier par taille Plus petit→Plus grand" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Trier par taille Plus grand→Plus petit" #: sabnzbd/skintext.py msgid "Uploading" msgstr "Upload en cours" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "Déconnexion forcée en cours" #: sabnzbd/skintext.py msgid "Removing job" msgstr "Suppression de la tâche" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "Suppression des tâches" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Préc." #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Suiv." #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Vider l'historique ?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Vous devez activer JavaScript pour que Plush puisse fonctionner !" #: sabnzbd/skintext.py msgid "Options" msgstr "Options" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Mettre en pause pour combien de minutes ?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Afficher/Masquer menu" #: sabnzbd/skintext.py msgid "On Finish" msgstr "Une fois terminé" #: sabnzbd/skintext.py msgid "Sort" msgstr "Trier" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Trier par âge (Moins récent→Plus récent)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Trier par âge (Plus récent→Moins récent)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Trier par nom (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Trier par nom (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Trier par taille (Plus petit→Plus grand)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Trier par taille (Plus grand→Plus petit)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Vider la file d'attente ?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Réessayez toutes les tâches échouées de l'historique ?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Vider" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Vitesse max." #: sabnzbd/skintext.py msgid "Range" msgstr "Plage" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Appliquer à la sélection" #: sabnzbd/skintext.py msgid "Everything" msgstr "Tout" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Fréquence de rafraîchissement" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Largeur de l'affichage" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "" "Permet d'éviter le rafraîchisssment du contenu quand la souris survole la " "file d'attente." #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Bloquer rafraîchissements au survol" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Envoyer" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Uploader : .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Avancement" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Espace disque insuffisant pour terminer les téléchargements!" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Libre (Temp)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "A L'ARRET" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Téléchargements" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Supprimer les terminés" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Supprimer tous les éléments échoués de l'historique ?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Supprimer les échoués" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Réessayez toutes les tâches qui ont échoué ?" #: sabnzbd/skintext.py msgid "Links" msgstr "Liens" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Affiche %s de %s sur %s résultats" #: sabnzbd/skintext.py msgid "No results" msgstr "Aucun résultat(s)" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Affichage d'un seul résultat" #: sabnzbd/skintext.py msgid "First" msgstr "Premier" #: sabnzbd/skintext.py msgid "Last" msgstr "Dernier" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "Email envoyé !" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Notification envoyée !" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Enregistrement.." #: sabnzbd/skintext.py msgid "Saved" msgstr "Enregistré" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Afficher / Masquer Ajout NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "VueDuoV" #: sabnzbd/skintext.py msgid "DualView2" msgstr "VueDuoH" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Êtes-vous sûr de vouloir redémarrer SABnzbd ?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Cacher les options d'édition" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Afficher les options d'édition" #: sabnzbd/skintext.py msgid "Edit" msgstr "Éditer" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Temps restant" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "Assistant de configuration SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "Version de SABnzbd" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Précédent" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Détails du serveur" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Entrez les informations de votre principal fournisseur usenet." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Le nombre de connexions autorisées par votre fournisseur usenet" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "Ex. : 8 ou 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "" "Cochez uniquement si votre fournisseur usenet permet les connexions SSL." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Cliquez pour tester les informations entrées." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Par ex. :" #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "La configuration est terminée!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd fonctionnera dorénavant en arrière plan." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "" "Fermer la fenêtre/onglet de votre navigateur NE QUITTERA PAS SABnzbd." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Il est recommandé de faire un clic-droit et d'ajouter cette page à vos " "favoris pour accéder à SABnzbd quand il tourne en arrière plan." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Une aide supplémentaire peut être trouvée sur notre" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Aller à SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Quitter SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Lancer l'assistant" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd est fourni sans AUCUNE GARANTIE.\n" "Ce logiciel est gratuit, et vous êtes invité à le redistribuer sous " "certaines conditions.\n" "Il est distribué sous licence GNU GENERAL PUBLIC LICENSE Version 2 ou toute " "autre version ultérieure.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "Pour pouvoir télécharger sur les newsgroups, il est nécessaire d'avoir un " "fournisseur usenet. Votre FAI peut vous fournir un accès, cependant un " "fournisseur usenet premium est recommandé." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "" "Vous n'avez pas de fournisseur usenet? Nous vous recommendons d'essayer %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Erreur lors de l'obtention des information TV (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Échec du renommage : %s en %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Impossible de renommer le fichier similaire : %s en %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Resolution du nom de serveur impossible" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Accès non autorisé" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "Fichier introuvable sur le serveur" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "Le serveur n'a pas pu terminer la requête" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "L'URLGRABBER A PLANTÉ" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Fichier NZB inutilisable" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "Échec de récupération de l'URL ; %s" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "Erreur CRC dans %s (%s -> %s)" #~ msgid "Error: No secondary interface defined." #~ msgstr "Erreur : Pas d'interface secondaire définie." #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "La version de votre binaire UNRAR n'est pas recommandée, Vous pouvez " #~ "l'obtenir ici http://www.rarlab.com/rar_add.htm
" #~ msgid "Initiating restart...
" #~ msgstr "Initialisation du redémarrage...
" #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "%s a été remis en file d'attente" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "" #~ "Les éléments marqués avec '*' ne seront pas automatiquement téléchargés." #~ msgid "Not matched" #~ msgstr "Ne correspond pas" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Impossible de se connecter au registre HKEY_CURRENT_USER." #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Impossible d'ouvrir la clé de registre \"%s\"." #~ msgid "You have no permisson to use port %s" #~ msgstr "Le port %s n'est pas accessible" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Le fichier attendu est manquant : %s => erreur unrar ?" #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Erreur lors de l'importation du module OpenSSL. Connection sans SSL" #~ msgid "View script output" #~ msgstr "Voir le résultat du script" #~ msgid "WARNINGS" #~ msgstr "AVERTISSEMENTS" #~ msgid "Add new downloads" #~ msgstr "Ajouter de nouveaux téléchargements" #~ msgid " or Report ID" #~ msgstr " ou Report ID" #~ msgid "Sort by name" #~ msgstr "Trier par nom" #~ msgid "Sort by age" #~ msgstr "Trier par âge" #~ msgid "Sort by size" #~ msgstr "Trier par taille" #~ msgid "Remain/Total" #~ msgstr "Restant/Total" #~ msgid "History Size" #~ msgstr "Taille Historique" #~ msgid "Show Weblogging" #~ msgstr "Afficher les weblogs" #~ msgid "Activate an alternative skin." #~ msgstr "Choisissez un thème pour la 2nde interface web." #~ msgid "HTTPS Support" #~ msgstr "Support HTTPS" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "" #~ "Intervalle de rafraichissement dans l'interface web (en sec, 0=aucun)." #~ msgid "Disable API-key" #~ msgstr "Désactiver la clé API" #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "A utiliser à vos risques et périls!" #~ msgid "Folder configuration" #~ msgstr "Configuration des dossiers" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "Dossier contenant les scripts utilisés lors du post-traitement." #~ msgid "Switches configuration" #~ msgstr "Configuration des options" #~ msgid "Processing Switches" #~ msgstr "Options de traitement" #~ msgid "Enable Unrar" #~ msgstr "Activer Unrar" #~ msgid "Enable built-in unrar functionality." #~ msgstr "Activer la fonctionnalité unrar intégrée." #~ msgid "Enable built-in unzip functionality." #~ msgstr "Activer la fonctionnalité unzip intégrée." #~ msgid "Default Post-Processing" #~ msgstr "Post-traitement par défaut" #~ msgid "Default User Script" #~ msgstr "Script utilisateur par défaut" #~ msgid "Default Priority" #~ msgstr "Priorité par défaut" #~ msgid "Other Switches" #~ msgstr "Autres options" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Remplacer les caractères illégaux dans les noms de dossier" #~ msgid "Do not download" #~ msgstr "Ne pas télécharger" #~ msgid "Click below to test." #~ msgstr "Cliquer ci-dessous pour tester." #~ msgid "Remove" #~ msgstr "Supprimer" #~ msgid "RSS Configuration" #~ msgstr "Configuration RSS" #~ msgid "Delete Feed" #~ msgstr "Supprimer le flux" #~ msgid "User-defined categories" #~ msgstr "Catégories utilisateur" #~ msgid "Defines post-processing and storage." #~ msgstr "Définit le post-traitement et le stockage." #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Active le classement et le renommage des épisodes." #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Activer si les téléchargement ne sont pas dans leur propre dossier." #~ msgid "Are you sure you want to delete" #~ msgstr "Etes-vous sûr de vouloir supprimer ?" #~ msgid "Close" #~ msgstr "Fermer" #~ msgid "Pause for 12 hours" #~ msgstr "Pause pour 12 heures" #~ msgid "Pause for 24 hours" #~ msgstr "Pause pour 24 heures" #~ msgid "Open Source URL" #~ msgstr "Ouvrir URL Source" #~ msgid "Plush Options" #~ msgstr "Options Plush" #~ msgid "Hour:Min" #~ msgstr "Heure:Min" #~ msgid "Access" #~ msgstr "Accès" #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Je veux que SABnzbd ne soit accessible que depuis mon ordinateur." #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "" #~ "Lancer mon navigateur internet avec l'adresse de SABnzbd au démarrage de " #~ "l'application." #~ msgid "Please enter a whole number." #~ msgstr "Entrez un numéro." #~ msgid " " #~ msgstr " " #~ msgid "Page" #~ msgstr "Page" #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "" #~ "Protection de l'interface de SABnzbd par un mot de passe (recommandé)" #~ msgid "Web server authentication" #~ msgstr "Authentification Serveur Web" #~ msgid "New Feed URL" #~ msgstr "URL Nouveau Flux" #~ msgid "Scheduling configuration" #~ msgstr "Configuration de la planification" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd n'est pas compatible avec certains pare-feu logiciels.
\n" #~ " %s
\n" #~ " Désolé, mais nous ne pouvons pas résoudre cette incompatibilité pour le " #~ "moment.
\n" #~ " S'il vous plaît faite une demande à l'éditeur de votre pare-feu.
\n" #~ "
\n" #~ msgid "OK" #~ msgstr "OK" #~ msgid "Backup server" #~ msgstr "Serveur de soutien" #~ msgid "Feeds" #~ msgstr "Flux" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Utiliser V23 à moins que votre fournisseur exige un autre type!" #~ msgid "Complete Dir" #~ msgstr "Dossier Complet" #~ msgid "Left" #~ msgstr "Restant" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "Utilise les serveurs de soutien si il y a des erreurs CRC yEnc." #~ msgid "Get NZB" #~ msgstr "Récupérer NZB" #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Échec de la lecture des clés de registre pour les dossiers spéciaux" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "" #~ "Échec de la suppression du nzo de la file d'attente de post-traitement (id)" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "Ex: 119 ou 563 pour le SSL" #~ msgid "Filters" #~ msgstr "Filtres" #~ msgid "Delete all failed items from History?" #~ msgstr "Supprimer tous les éléments erronés de l'historique?" #~ msgid "Purge Failed History" #~ msgstr "Purger Historique erronés" #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Échec lors d'erreurs CRC yEnc" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "Utilisé quand la catégorie ne précise pas de choix." #~ msgid "Used when no user script is defined by the category." #~ msgstr "Utilisé quand la catégorie ne précise pas de script." #~ msgid "Used when no priority is defined by the category." #~ msgstr "Utilisé quand la catégorie ne précise pas de priorité." #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Remplace les caractères illégaux dans les noms de dossier par des " #~ "équivalents (sinon les supprime)." #~ msgid "Server configuration" #~ msgstr "Configuration du Serveur" #~ msgid "Server definition" #~ msgstr "Définition du Serveur" #~ msgid "Add Feed" #~ msgstr "Ajouter un flux" #~ msgid "Settings" #~ msgstr "Paramètres" #~ msgid "Sorting configuration" #~ msgstr "Configuration du tri" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Active le tri et le renommage générique des fichiers." #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Active le tri et le renommage des fichiers par date." #~ msgid "folder" #~ msgstr "dossier" #~ msgid "Set Pause Interval" #~ msgstr "Intervalle de pause" #~ msgid "Storage" #~ msgstr "Stockage" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Envoyer : .nzb .rar .zip .gz" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Lire RSS obtient le contenu du flux en cours. " #~ "Forcer téléchargements pour télécharger de suite tous les " #~ "NZB correspondants." #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Activer l'accès à SABnzbd via HTTPS." #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "" #~ "Je veux que SABnzbd soit accessible à partir de tous les ordinateurs de mon " #~ "réseau." #~ msgid "Misc" #~ msgstr "Divers" #~ msgid "This field is required." #~ msgstr "Ce champ est obligatoire." #~ msgid "Step One" #~ msgstr "Étape 1" #~ msgid "Step Two" #~ msgstr "Étape 2" #~ msgid "Step Three" #~ msgstr "Étape 3" #~ msgid "Step Four" #~ msgstr "Étape 4" #~ msgid "Step Five" #~ msgstr "Étape 5" #~ msgid "Pause Interval" #~ msgstr "Intervalle pause" #~ msgid "Check result of unpacking" #~ msgstr "Vérifier le résultat de l'extraction" #~ msgid "Only for optional servers" #~ msgstr "Uniquement pour les serveurs optionnels" #~ msgid "Show files" #~ msgstr "Afficher les fichiers" #~ msgid "SQL Commit Failed, see log" #~ msgstr "Echec du commit SQL, voir le journal" #~ msgid "Downloaded so far" #~ msgstr "Téléchargé jusqu'à présent" #~ msgid "Try again" #~ msgstr "Réessayer" #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Fichiers par2 non valides, impossible de vérifier ou réparer" #~ msgid "KB/s" #~ msgstr "kbit/s" #~ msgid "Queued" #~ msgstr "Mis en file d'attente" #~ msgid "Download speed" #~ msgstr "Vitesse de téléchargement" #~ msgid "Thread" #~ msgstr "Traitement" #~ msgid "General configuration" #~ msgstr "Configuration générale" #~ msgid "Queue auto refresh interval:" #~ msgstr "Intervalle de rafraîchissement automatique de la file d'attente:" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Dossier des scripts de post-traitement" #~ msgid "QR Code" #~ msgstr "Code QR" #~ msgid "Enable Par Cleanup" #~ msgstr "Activer nettoyage Par" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Utiliser l'horloge 12 heures (AM/PM)" #~ msgid "Secondary Web Interface" #~ msgstr "Interface Web secondaire" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Affiche l'heure au format AM/PM (n'affecte pas la planification)." #~ msgid "SSL type" #~ msgstr "Type SSL" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "" #~ "Supprime les fichiers Par2 (uniquement si la vérification/réparation a " #~ "réussie)." #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Vérifie le résultat de l'extraction (doit être désactivée pour certains " #~ "systèmes de fichiers)." #~ msgid "Email Options" #~ msgstr "Options email" #~ msgid "Email Account Settings" #~ msgstr "Paramètres du compte email" #~ msgid "Generic Sorting" #~ msgstr "Tri générique" #~ msgid "Notification classes" #~ msgstr "Classes de notification" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "" #~ "Activer les classes de messages qui doivent être communiqués (aucun, un ou " #~ "plusieurs)" #~ msgid "Refer to https://www.oznzb.com/profile" #~ msgstr "Reportez-vous à https://www.oznzb.com/profile" #~ msgid "Automatic Feedback" #~ msgstr "Commentaires automatique" #~ msgid "Site API Key" #~ msgstr "Clé API du site" #~ msgid "Enable OZnzb Integration" #~ msgstr "Activer l'intégration de OZnzb" #~ msgid "OZnzb" #~ msgstr "OZnzb" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "" #~ "Envoyer les résultats de la validation calculées automatiquement pour les " #~ "téléchargements à l'indexeur." #~ msgid "Folder \"%s\" does not exist" #~ msgstr "Le dossier \"%s\" est introuvable" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "AVERTISSEMENT : mise en pause de \"%s\" à cause de fichiers RAR cryptés" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "AVERTISSEMENT : tâches \"%s\" interrompues à cause de fichiers RAR cryptés" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "" #~ "Aucun programme PAR2 n'a été trouvé, les réparations ne sont pas " #~ "possibles
" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "module pyopenssl manquant, veuillez l'installer pour l'accès HTTPS" #~ msgid "Main packet not found..." #~ msgstr "Paquet principal introuvable..." #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd a besoin d'un port tcp/ip libre pour le serveur Web " #~ "interne.
\n" #~ " La plage de ports %s a %s a été essayée mais le compte utilisé pour " #~ "SABnzbd n'a pas la permission de l'utiliser.
\n" #~ " Sur les systèmes OSX et Linux, les utilisateurs normaux doivent utiliser " #~ "des ports supérieurs à 1023.
\n" #~ "
\n" #~ " Veuillez redémarrer SABnzbd avec un port différent." #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Il est probable que vous utilisiez ZoneAlarm sur Vista.
" #~ msgid "Hide files" #~ msgstr "Masquer les fichiers" #~ msgid "Email Test Result" #~ msgstr "Résultat du test e-mail" #~ msgid "Do not require the API key." #~ msgstr "Ne pas exiger la clé API (pour l'interaction avec SABnzbd)." #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Ignorer la vérification par2 quand les fichiers sont valides à 100%." #~ msgid "Enable Quick Check" #~ msgstr "Activer le contrôle rapide" #~ msgid "Enable Filejoin" #~ msgstr "Activer la fusion des fichiers" #~ msgid "Enable TS Joining" #~ msgstr "Activer la fusion TS" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "Fusionner les fichiers .001, .002, etc. en un seul fichier." #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "Fusionne les fichiers .001.ts, .002.ts, etc. en un seul fichier." #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "" #~ "Aucun programme UNRAR n'a été trouvé, l'extraction des fichiers RAR est " #~ "impossible
" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "L'extraction a échoué, ces fichiers sont manquants :" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "Échec de l'extraction, un fichier attendu n'a pas été décompressé" #~ msgid "Enable MultiCore Par2" #~ msgstr "Activer le 'Par2 Multi-processeur'" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Applique les tentatives maximums uniquement aux serveurs optionnels" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Cette clé fournit l'identité à l'indexeur. Reportez-vous à " #~ "https://www.oznzb.com/profile." #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Activer les fonctionnalités avancées comme les classements et les " #~ "informations d'état supplémentaires quand connecté à l'indexer OZnzb." #~ msgid "Skip" #~ msgstr "Ignorer" #~ msgid "Groups / Indexer tags" #~ msgstr "balises Groupes / Indexeur" #~ msgid "Original Foldername" #~ msgstr "Nom du dossier originel" #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "Après que SABnzbd a fini de redémarrer, vous serez en mesure d'y accéder à " #~ "l'adresse suivante : %s" SABnzbd-2.3.2/po/main/he.po0000644000000000000000000044657113217005051013440 0ustar 00000000000000# Hebrew translation for sabnzbd # Copyright (c) 2017 Rosetta Contributors and Canonical Ltd 2017 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2017. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2017-12-06 19:50+0000\n" "Last-Translator: ION IL \n" "Language-Team: Hebrew \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:30+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "נכשל בהתחלת ממשק רשת" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "מנסה תבנית תקנית ,%s :לא ניתן למצוא תבניות רשת" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "מושבת: לא נמצאה גרסה נכונה! (נמצאה %s מצפה אל %s) SABYenc" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "%s - https://sabnzbd.org/sabyenc לא נמצא! מצפה אל ...SABYenc פירקן" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "!לא נמצא ..._yenc פירקן" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "!בינארי... לא נמצא par2" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr ".וידוא ותיקון לא יהיו אפשריים" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "!בינארי... לא נמצא MultiPar" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr ".שלך היא %s אנו ממליצים על גרסה %s או גבוהה יותר UNRAR גרסת
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr ".הורדות לא ייפרקו" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "בינארי... לא נמצא unrar" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "!בינארי... לא נמצא unzip" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "!בינארי... לא נמצא za7" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "עבור גישה חיצונית IPv6 אנא היה מודע ששם המארח 0.0.0.0 יצטרך כתובת" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "אינן יכולות להיות אותו דבר HTTPS-ו HTTP פתחות של" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" ".של קבצים וספריות בהורדות Unicode צפה לבעיות עם שמות .UTF-8 היא אמורה להיות " ",%s הותחל עם הצפנת SABnzbd" #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "KEY-ו CERT בגלל קבצים חסרים של HTTPS השבית את" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "נכשל בהתחלת ממשק-רשת: " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "SABHelper לא ניתן לגשת אל השירות" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "התחיל SABnzbd %s" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "אזהרה" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "שגיאה" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "הסתיים SABnzbd כיבוי" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr ".שם המארח לא נקבע" #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr ".אין חיבורים שנקבעו. אנא קבע לפחות חיבור אחד" #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "סיסמאות מוסוות ב-******, אנא הכנס מחדש" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "פרטי שרת בלתי תקפים" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr ".או להתחבר על פתחה שונה SSL אזל הזמן: נסה לאפשר" #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "אזל הזמן" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr ".או להתחבר על פתחה שונה SSL בלתי ידוע: נסה להשבית SSL פרוטוקול" #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr ".כתובת שרת בלתי תקפה" #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr ".שרת יצא במהלך רצף כניסות" #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr ".השרת דורש שם משתמש וסיסמה" #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "!חיבור מוצלח" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr ".אימות נכשל, בדוק שם משתמש/סיסמה" #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "יותר מדי חיבורים, אנא השהה הורדה או נסה שוב מאוחר יותר" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "(%s) לא היה ניתן לקבוע תוצאת חיבור" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "...נתפס, שומר ויוצא %s אות" #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "שגיאה חמורה במצב שמירה" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "%s-מ NZB מנסה למשוך" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "שמירת %s נכשלה" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "%s לא ניתן ליצור קובץ זמני עבור" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "%s מנסה לקבוע מצב של שרת בלתי-קיים" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "tempfile.mkstemp-כישלון ב" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "נכשלה %s טעינת" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "%s נכשלה עם שגיאה %s טעינת" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "בחן התראה" #: sabnzbd/api.py msgid " Resolving address" msgstr " פותר כתובת" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "ללא" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "ברירת מחדל" #: sabnzbd/api.py msgid "unknown" msgstr "בלתי ידוע" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "%s :עבור מונח חיפוש regex נכשל בליקוט" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "שטח דיסק קטן מדי, מאלץ השהיה" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "דיסק מלא! מאלץ השהיה" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "%s שגיאת דיסק ביצירת קובץ" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Assembler-שגיאה חמורה ב" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" "(מוצפן (במקרה שסופקה, כל הסיסמאות נוסו RAR בגלל קובץ \"%s\" אזהרה: השהה את " "העבודה" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" "(מוצפן (במקרה שסופקה, כל הסיסמאות נוסו RAR בגלל קובץ \"%s\" אזהרה: ביטל את " "העבודה" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "בוטל, הצפנה התגלתה" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "%s קובץ בלתי רצוי הוא .RAR סיומת בלתי רצויה בקובץ \"%s\"-אזהרה: ב " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "%s rar סיומת בלתי רצויה בקובץ" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "בוטל, סיומת בלתי רצויה התגלתה" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "(%s) בגלל מידרג \"%s\" אזהרה: השהה את העבודה" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "(%s) בגלל מידרג \"%s\" אזהרה: ביטל את העבודה" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "(%s) בוטל, מסנן מידרג הותאם" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s חסרים" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "זה RAR עם אותו השם בתוך RAR כנראה מוצפנת עקב \"%s\" העבודה" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "\"%s\" כנראה מוצפנת: \"סיסמה\" בשם הקובץ \"%s\" העבודה" #: sabnzbd/assembler.py msgid "video" msgstr "וידאו" #: sabnzbd/assembler.py msgid "audio" msgstr "שמע" #: sabnzbd/assembler.py msgid "spam" msgstr "זבל" #: sabnzbd/assembler.py msgid "passworded" msgstr "מוגן בסיסמה" #: sabnzbd/assembler.py msgid "downvoted" msgstr "הוצבע נגד" #: sabnzbd/assembler.py msgid "keywords" msgstr "מילות מפתח" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "מיכסה נוצלה, משהה הורדה" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "אינה כתובת דוא\"ל תקפה %s" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "כתובת שרת דרושה" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "%s תיקייה %s לא יכול ליצור" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "%s קובץ INI לא ניתן לכתוב אל" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "%s לא ניתן ליצור קובץ גיבוי עבור" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "%s סיסמה מוצפנת באופן שגוי" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s אינו ערך אוקטלי נכון" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "אינו מותר כאן \"%s\" UNC נתיב" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr ".שגיאה: אורך הנתיב צריך להיות מתחת אל %s" #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr ".שגיאה: התור אינו ריק, לא יכול לשנות תיקייה" #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "!לא ניתן לכתוב במסד-נתונים של היסטוריה, בדוק זכויות גישה" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "מסד-נתונים היסטוריה פגום, נוצר תחליף ריק" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "נכשלה, ראה יומן SQL פקודת" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "נכשל בסגירת מסד-נתונים, ראה יומן" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "%s התחברות שלב בלתי תקפה בהיסטוריה עבור" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "נכשל %s פענוח" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "כישלון מפענח: אין זיכרון" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "%s-נוצר באופן גרוע ב yEnc מאמר" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "%s שגיאה בלתי ידועה בעת פענוח" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "[%s] נתמכת yEnc התגלה, רק הצפנת UUencode" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "חסר מכל השרתים, משליך <= %s" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "פריקה ישירה" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "הושלם" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "פורקו %s קבצים/תיקיות תוך %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr ".פריקה ישירה אופשרה באופן אוטומטי" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" ".עבודות יתחילו להיפרק במהלך ההורדה כדי להפחית זמן בתר-עיבוד. עובד רק עבור " "עבודות שאינן צריכות תיקון" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "לא יכול לקרוא את %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "מסיר ,%s שגיאה בזמן הוספת" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "%s שגיאה בהסרת" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "%s לא ניתן לקרוא את התיקייה המושגחת" #: sabnzbd/downloader.py msgid "Resuming" msgstr "ממשיך" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "מושהה" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "אתה חייב לקבוע רוחב פס מרבי לפני שאתה קובע מגבלת רוחב פס" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "ייתקל בהתעלמות למשך %s דקות %s השרת" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "%s :מהסיבה %s@%sנכשל באתחול" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "%s יותר מדי חיבורים לשרת" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "שיתוף סביר של חשבון" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "%s נכשל בכניסה לשרת" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "%s [%s] לא ניתן להתחבר לשרת" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "%s=נכשלה, הודעה %s@%s התחברות אל" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "דורש שם משתמש/סיסמה %s השרת" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "הורדה חשודה במורידן" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "מכבה" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "נכשל בהתחברות לשרת דוא\"ל" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "TLS נכשל ביזימת חיבור" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "השרת לא הגיב כראוי לברכת השלום" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "נכשל באימות שרת הדוא\"ל" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "לא נמצאה שיטת אימות הולמת" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "כישלון בלתי ידוע של אימות בשרת דוא\"ל" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "נכשל בשליחת דוא\"ל" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "נכשל בסגירת חיבור דוא\"ל" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "דוא\"ל הצליח" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "לא ניתן לשלוח, נתונים דרושים חסרים" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "%s-לא ניתן למצוא תבניות דוא\"ל" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "לא ניתנו נמענים, לא נשלח דוא\"ל" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "%s הצפנה בלתי תקפה של תבניות דוא\"ל" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "לא נמצאו תבניות דוא\"ל" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "%s :אל\n" "%s :מן\n" "תאריך: %s\n" "מדווח על דיסק מלא SABnzbd :נושא\n" "\n" ",היי\n" "\n" ".הפסיק להוריד, מאחר שהדיסק כמעט מלא\n" ".באופן ידני SABnzbd אנא פנה מקום והמשך את\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr ".מספרית IP הוא דו-משמעי, השתמש בכתובת LOCALHOST :אזהרה" #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr ".אינה תקפה \"%s:%s\" כתובת השרת" #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "משתמש התחבר לממשק הרשת" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "משתמש התחבר" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "מפתח חסר של שיח" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "שגיאה: מפתח דרוש של שיח" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "שגיאה: מפתח לא נכון של שיח" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "מתצורה->כללי לתוך תכנית הצד השלישי שלך api-חסר, אנא הכנס את מפתח ה API מפתח:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "מתצורה->כללי בתכנית הצד השלישי שלך api-אינו נכון, השתמש במפתח ה API מפתח:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" ":אימות חסר, אנא הכנס שם משתמש/סיסמה מתוך תצורה->כללי לתוך תכנית הצד השלישי " "שלך" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "עיצוב חדש רענן המיועל עבור שולחן עבודה והתקנים ניידים. לך אל תצורה -> כללי " "כדי לשנות את עורך !Glitter נסה את העור החדש שלנו" #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "%s-ניסיון כניסה בלתי מוצלחת מ" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "ב" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
.הסתיים SABnzbd כיבוי
.המתן בערך 5 שניות ואז לחץ על הכפתור " "למטה

רענן
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "הזנה" #: sabnzbd/interface.py msgid "Daily" msgstr "יומי" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "יום שני" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "יום שלישי" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "יום רביעי" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "יום חמישי" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "יום שישי" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "שבת" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "יום ראשון" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "כבוי" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "!שרת בלתי מוגדר" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "משתנה לא נכון" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr ".תיקיית מדור אינה יכולה להיות תת-תיקייה של תיקיית ההורדות הזמניות" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "הקודם" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "שגיאה:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "%s: %s ערך לא נכון עבור" #: sabnzbd/misc.py msgid "d" msgstr "י" #: sabnzbd/misc.py msgid "h" msgstr "ש" #: sabnzbd/misc.py msgid "m" msgstr "ד" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "%s לא יכול ליצור את הספרייה" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "%s שגיאת גישה :%s ספרייה" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "(%s) נכשל בעשיה" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "%s אל %s נכשל בהעברת" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "SSL נכשל ביצירה של מפתח ואישור של" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" ".קובץ הסיסמאות שלך מכיל יותר מ-30 סיסמאות, בחינת כל הסיסמאות האלו תיקח זמן " "רב. נסה לכתוב ברשימה רק סיסמאות שימושיות" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "%s לא יכול לשנות הרשאות של" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "מריץ תסריט" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "(%s) בתר-עיבוד בוטל" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "תסריט" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "[%s] פריקת קינון ארוכה מדי" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "מאחד" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "רצף בלתי שלם של קבצים ברי-איחוד" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "נכשל %s איחוד קבצים של" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "שגיאה \"%s\" בזמן איחוד קבצים [%s]" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "%s שגיאה \"%s\" בזמן הרצת איחוד_קבצים ב" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] איחד %s קבצים" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "%s ,פריקה נכשלה" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "RAR [%s] שגיאה \"%s\" בזמן פריקת קבצי" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "%s על rar_unpack שגיאת \"%s\" בזמן הרצת" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "!נכשלה %s מחיקת" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "\"%s\" מנסה לחלץ עם הסיסמה" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "פריקה נכשלה, ארכיון דורש סיסמה" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "פורק" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "פרוק" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "%s פריקה נכשלה, לא היה ניתן למצוא את" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "\"%s\" שגיאה: לא היה ניתן למצוא את" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "פריקה נכשלה ,CRC שגיאת" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "\"%s\"-נכשל ב CRC :שגיאה" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "(FAT?) פריקה נכשלה, קובץ גדול מדי עבור מערכת קבצים" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "(%s) שגיאה: קובץ גדול מדי עבור מערכת הקבצים" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "?פריקה נכשלה, שגיאת כתיבה או דיסק מלא" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "(%s) שגיאה: שגיאת כתיבה" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "פריקה נכשלה, נתיב ארוך מדי" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "(%s) שגיאה: נתיב ארוך מדי" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "פריקה נכשלה, ראה יומן אירועים" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "%s :שגיאה" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "בלתי שמיש RAR קובץ" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "פגום RAR קובץ" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s קבצים ב %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "%s על unzip() שגיאת \"%s\" בזמן הרצת" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "\"%s\" עם הסיסמה 7zip מנסה" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "אינה שלמה, לא יכול לפרוק \"%s\" ZIP7 ערכת" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "%s לא היה ניתן לפרוק את" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "בדיקה זריזה" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "תיקון" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] בדיקה זריזה בסדר" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "מתחיל תיקון" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "!בעוד שבדיקה זריזה הצליחה ,%s-נכשל ב Par וידוא" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "%s ,תיקון נכשל" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "%s על ערכת par2_repair בזמן הרצת %s שגיאת" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "%s על ערכת par2_repair בזמן הרצת \"%s\" שגיאה" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "קיבל אפשרויות שגויות, בדוק את קביעות תצורה->מתגים שלך PAR2 [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "כל הקבצים נכונים ,%s-[%s] וודאו ב" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "תיקון דרוש ,%s-[%s] וודאו ב" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" "בלתי תקפים, לא יכול לוודא או לתקן PAR2 בלתי תקפים או פרמטרי par2 קבצי" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "...מושך %s גושים" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "מושך" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "(קצר %s) תיקון נכשל, אין מספיק גושי תיקון" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "מתקן" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "%s-תוקן ב [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "מוודא תיקון" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "דיסק מלא" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "מוודא" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "בודק קבצי תוספת" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "בודק" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "(+x) אין ערכת הרשאות ביצוע \"%s\" לתסריט פייתון" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "בפתחה זו SSL שרת זה אינו מתיר" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" ".שם מארח של האישור אינו תואם: שם המארח של השרת אינו מופיע ברשימה באישור. זו " "סוגית שרת" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr ".אישור אינו תקף. קרוב לוודאי שזו סוגית שרת" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "[%s] משתמש באישור בלתי מהימן %s השרת" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "וויקי" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "אתחול / כיבוי" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "התווסף NZB" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "בתר-עיבוד התחיל" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "עבודה הסתיימה" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "עבודה נכשלה" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "תור הסתיים" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "הודעות אחרות" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "לא זמין" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Prowl נכשל בשליחת הודעת" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Pushover (%s): %s-תגובה רעה מ" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "pushover נכשל בשליחת הודעת" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Pushbullet (%s): %s-תגובה רעה מ" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "pushbullet נכשל בשליחת הודעת" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "\"%s\" תסריט החזיר קוד יציאה %s ופלט" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "אינו קיים \"%s\" תסריט התראות" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "Windows נכשל בשליחת התראת" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "תור ישן התגלה, השתמש במצב->תיקון כדי להמיר את התור" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "קובץ תור בלתי תואם נמצא, לא יכול להמשיך" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "התגלה קובץ פגום ,%s שגיאה בטעינת" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "(%s) לאחר קדם-בדיקה NZB נכשל בהפעלה מחדש של" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "התווסף לתור NZB" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "הצפנה בלתי ידועה <- %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "ריק, מדלג %s הקובץ" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "%s נכשל ביבוא %s קבצים מ" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "%s בלתי שלם NZB קובץ" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "מדלג ,%s בלתי תקף NZB קובץ (סיבה=%s שורה=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "%s ריק NZB קובץ" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "תסריט קדם-תור סומן כנכשל" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "\"%s\" כפול NZB-מתעלם מ" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "\"%s\" NZB נכשל בשכפול" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "NZB שכפל" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "\"%s\" NZB משהה שכפול" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "בוטל, לא יכול להיות שלם" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "כפול" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "מוצפן" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "גדול מדי" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "בלתי שלם" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "בלתי רצוי" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "מסונן" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "המתן %s שניות" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "מפיץ %s דקות" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "לשנייה %sB הורד תוך %s בממוצע של" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "גיל" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s מאמרים עוותו" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s מאמרים היו חסרים" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "ל-%s מאמרים יש כפילויות בלתי-תואמות" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s מאמרים הוסרו" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "%s שגיאה ביבוא" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "אזהרות" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "סרק" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "תצורה" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "תור" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "טהר תור" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "היסטוריה" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "טהר היסטוריה" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "הגבל מהירות" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "השהה" #: sabnzbd/osxmenu.py msgid "min." msgstr "דק." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "המשך" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "סרוק תיקייה מושגחת" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "RSS קרא את כל הזנות" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "תיקייה שלמה" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "תיקייה בלתי שלמה" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "פתור בעיות" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "הפעל מחדש" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "הפעל מחדש ללא כניסה" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "צא" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "הוסף לתור 10 פריטים ראשונים" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "ריק" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "העבר להיסטוריה 10 פריטים אחרונים" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "שחרור חדש זמין" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "לך לאשף" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "עוצר..." #: sabnzbd/panic.py msgid "Problem with" msgstr "בעיה עם" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " .עבור שרת הרשת הפנימי שלו tcp/ip צריך פתחה חופשית של SABnzbd
\n" " .פתחה %s על %s נוסתה, אך היא אינה זמינה
\n" " .כבר רץ SABnzbd איזשהי תוכנה אחרת משתמשת בפתחה או
\n" "
\n" " .עם מספר פתחה אחר SABnzbd אנא הפעל מחדש את" #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr ".אם אתה מקבל את הודעת השגיאה הזו שוב, אנא נסה מספר שונה
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " .צריך כתובת מארח תקפה עבור שרת הרשת הפנימי שלו SABnzbd
\n" " .ציינת כתובת בלתי תקפה
\n" " ו-0.0.0.0 localhost ערכים בטוחים הם
\n" "
\n" " .עם כתובת מארח תקינה SABnzbd אנא הפעל מחדש את" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " אחרת SABnzbd גילה נתונים שמורים מגרסת SABnzbd
\n" " .אבל אינו יכול להשתמש מחדש בנתונים של התכנית האחרת

\n" " .אתה אולי תרצה לסיים את התור שלך תחילה עם התכנית האחרת

\n" " .\"--clean\" לאחר מכן, התחל תכנית זו עם האפשרות
\n" " !זה ימחק את התור וההיסטוריה הנוכחיים
\n" " .\"%s\" קרא את הקובץ SABnzbd" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " .%s-אינו יכול למצוא את קבצי ממשק הרשת שלו ב SABnzbd
\n" " .אנא התקן את התכנית שוב
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr ":גילה שגיאה חמורה SABnzbd" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " .חסר sqlite3.dll גילה שהקובץ SABnzbd

\n" " .מספר סורקי-נגיפים ירודים מסירים קובץ זה
\n" " .והתלונן למוכר סורק-הנגיפים שלך SABnzbd אנא בדוק את סורק-הנגיפים שלך, " "נסה להתקין מחדש את
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "והקלד את הקו (דוגמה): R+לחץ על מקש התחל" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "פתח חלון מסוף והקלד את הקו (דוגמה):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "!התכנית לא התחילה" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" ".כבר רץ SABnzbd איזשהי תוכנה אחרת משתמשת בפתחה או %s לא היה ניתן לקשר את " "פתחה %s על" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "שגיאה חמורה" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "לא היה ניתן להפעיל את הדפדפן, כנראה שהוא לא נמצא" #: sabnzbd/panic.py msgid "Access denied" msgstr "גישה נדחתה" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr ".שגיאה %s: אתה צריך לספק שם משתמש וסיסמה תקפים" #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" "המגבילה גודל מרבי של קובץ אל 4 ג\"ב ,FAT היא במערכת קבצים %s תיקיית ההורדות " "השלמות" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" ".של קבצים וספריות בהורדות Unicode חסר. צפה לבעיות עם שמות subprocessww פירקן" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "הורדה עשויה להיכשל, רק %s מתוך %s דרושים זמינים" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "הורדה נכשלה - לא בשרת(ים) שלך" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "אין בתר-עיבוד בגלל וידוא כושל" #: sabnzbd/postproc.py msgid "Moving" msgstr "מעביר" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "לתור %s שלח את" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "\"%s\" אל \"%s\" שגיאה בשינוי שם" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "נכשל בהעברת קבצים" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "%s מריץ תסריט משתמש" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "%s הריץ את" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "קוד יציאת תסריט הוא %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "עוד" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "%s (%s) בתר-עיבוד נכשל עבור" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "ראה קובץ יומן" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "הורדה נכשלה" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr ".נכשל %s ניקוי של" #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "(%s) שגיאה בהסרת תיקיית עבודה" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "הורדה הושלמה" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "%s לא יכול ליצור תיקייה סופית" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "בתר-עיבוד" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "par2 [%s] אין ערכות" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "SFV מנסה וידוא" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "\"%s\" מספר קבצים נכשלו בוידוא מול" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "SFV-וודא בהצלחה ע\"י שימוש ב" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "RAR מנסה וידוא מבוסס" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "%s :נכשל RAR וידוא מבוסס [%s]" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "מוגן בסיסמה" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "קבצי RAR וודאו בהצלחה" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "נכשלו בוידוא RAR קבצי" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "נכשלה %s הסרת" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "נכשל בחריפת מערכת" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "נכשל בהיכוננות מערכת" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "שגיאה בזמן כיבוי מערכת" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "לא נמצאה עבור קובץ מידרגים (%s) זהות מדדן" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "כתובת שרת" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "API מפתח" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr ".מפתח זה מספק זהות למדדן. בדוק את המתאר שלך באתר של המדדן" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "\"%s\" לא נכון RSS תיאור הזנת" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "%s: %s-מ RSS נכשל באחזור" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "%s אין אימות תקף עבור ההזנה" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "%s על %s שגיאה צדדית של שרת (קוד שרת %s); לא היה ניתן להשיג את" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "בלתי מהימן HTTPS משתמש באישור %s השרת" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "הייתה ריקה %s RSS הזנת" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "הזנה בלתי תואמת" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "(%s) ריקה נמצאה RSS כניסת" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "הראה ממשק" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "פתח תיקיית השלמה" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "כבה" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "נותר" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "NZB הוסף" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "ב-%s:%s %s תזמון גרוע" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "פעולה בלתי ידועה: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "%s תזמן עבור שרת בלתי-קיים" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "הורדה" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "אחד קבצים" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "מקור" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "שרתים" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "כישלון" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "נכשל" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "ממתין" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "מתקן..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "מחלץ..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "מעביר..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "מריץ תסריט..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "...מושך גושים נוספים" #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "...בדוק זריז" #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "...מוודא" #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "מוריד" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "עיכוב רביה" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "תדירות" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "פעולה" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "טיעונים" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "מטלה" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "השבת שרת" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "אפשר שרת" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "מגבלת מהירות" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "השהה הכל" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "השהה בתר-עיבוד" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "המשך בתר-עיבוד" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "RSS קרא הזנות" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "הסר עבודות נכשלות" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "הסר עבודות נשלמות" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "השהה עבודות עם עדיפות נמוכה" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "השהה עבודות עם עדיפות רגילה" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "השהה עבודות עם עדיפות גבוהה" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "המשך עבודות עם עדיפות נמוכה" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "המשך עבודות עם עדיפות רגילה" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "המשך עבודות עם עדיפות גבוהה" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "אפשר ניהול מיכסה" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "השבת ניהול מיכסה" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "השהה עבודות עם מדור" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "המשך עבודות עם מדור" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "כבוי" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "נמוכה מאוד" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "בינונית" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "רגילה" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "גבוהה" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "חירום" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "נמוכה" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "מ\"ב" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "ג''ב" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "שעה" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "שעות" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "דקה" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "דקות" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "שניה" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "שניות" #: sabnzbd/skintext.py msgid "day" msgstr "יום" #: sabnzbd/skintext.py msgid "days" msgstr "ימים" #: sabnzbd/skintext.py msgid "week" msgstr "שבוע" #: sabnzbd/skintext.py msgid "Month" msgstr "חודש" #: sabnzbd/skintext.py msgid "Year" msgstr "שנה" #: sabnzbd/skintext.py msgid "January" msgstr "ינואר" #: sabnzbd/skintext.py msgid "February" msgstr "פברואר" #: sabnzbd/skintext.py msgid "March" msgstr "מרץ" #: sabnzbd/skintext.py msgid "April" msgstr "אפריל" #: sabnzbd/skintext.py msgid "May" msgstr "מאי" #: sabnzbd/skintext.py msgid "June" msgstr "יוני" #: sabnzbd/skintext.py msgid "July" msgstr "יולי" #: sabnzbd/skintext.py msgid "August" msgstr "אוגוסט" #: sabnzbd/skintext.py msgid "September" msgstr "ספטמבר" #: sabnzbd/skintext.py msgid "October" msgstr "אוקטובר" #: sabnzbd/skintext.py msgid "November" msgstr "נובמבר" #: sabnzbd/skintext.py msgid "December" msgstr "דצמבר" #: sabnzbd/skintext.py msgid "Day of month" msgstr "יום בחודש" #: sabnzbd/skintext.py msgid "This week" msgstr "השבוע הזה" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "החודש הזה" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "היום" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "סה''כ" #: sabnzbd/skintext.py msgid "on" msgstr "פועל" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "משתנים" #: sabnzbd/skintext.py msgid "Python Version" msgstr "גרסת פייתון" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "דף הבית" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "או" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "מארח" #: sabnzbd/skintext.py msgid "Comment" msgstr "הער" #: sabnzbd/skintext.py msgid "Send" msgstr "שלח" #: sabnzbd/skintext.py msgid "Cancel" msgstr "ביטול" #: sabnzbd/skintext.py msgid "Other" msgstr "אחר" #: sabnzbd/skintext.py msgid "Report" msgstr "דווח" #: sabnzbd/skintext.py msgid "Video" msgstr "וידאו" #: sabnzbd/skintext.py msgid "Audio" msgstr "שמע" #: sabnzbd/skintext.py msgid "Not used" msgstr "לא בשימוש" #: sabnzbd/skintext.py msgid "or less" msgstr "או פחות" #: sabnzbd/skintext.py msgid "Log in" msgstr "התחבר" #: sabnzbd/skintext.py msgid "Log out" msgstr "התנתק" #: sabnzbd/skintext.py msgid "Remember me" msgstr "זכור אותי" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "אוטומטי usenet כלי הורדות" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "שמור" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "האם אתה בטוח?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "למחוק את כל הקבצים שהורדו?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "בית" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "הגדר" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "מצב" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "עזרה" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "פורום" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "סוגיות" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "!תמוך במיזם, תרום" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "כללי" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "תיקיות" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "מתגים" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "תזמון" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "התראות" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "דוא\"ל" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "מדורים" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "מיון" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "מיוחד" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "חיפוש" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "תיקיית הורדות" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "מושהה" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "(%s) מאמרים %s מוטמנים" #: sabnzbd/skintext.py msgid "Sysload" msgstr "עומס מערכת" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "שחרור חדש %s זמין ב" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "?SABnzbd האם אתה בטוח שברצונך לכבות את" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "הוסף" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "הוסף קובץ" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "מדור" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "מעבד" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "עדיפות" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+תיקון" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+פריקה" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+מחיקה" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "ת" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "ח" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "מ" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "אילוץ" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "עצירה" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "הכנס כתובת" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "בסיום תור" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "כבה מחשב" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "היכון מחשב" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "חרוף מחשב" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "SABnzbd כבה את" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "מגבלת מהירות" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "השהה למשך" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "סידור" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "שם" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "זמן משוער" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "גיל" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "מחק" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "נסה שוב" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "פעולות" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "תסריטים" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "למחוק את כל הפריטים מהתור?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "NZB טהר" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "ומחק קבצים NZB טהר" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "נסה שוב את כל העבודות הנכשלות" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "NZB הסר" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "ומחק קבצים NZB הסר" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "מתוך" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "מאמרים חסרים" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "מיכסה שנותרה" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "ידני" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "אפס מיכסה כעת" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "?למחוק את כל הפריטים השלמים מההיסטוריה" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "הסתר פרטים" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "הראה פרטים" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "הראה נכשלים" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "הראה הכל" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "גודל" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "נכשלים NZB טהר" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "נכשלים ומחק קבצים NZB טהר" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "שהושלמו NZB טהר" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "בדף הנוכחי NZB טהר" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "משלים רשותי NZB" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "נתיב" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "נסה שוב כל הנכשלים" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "נסה שוב הכל" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "נגיף/דואר זבל" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "אין שימור" #: sabnzbd/skintext.py msgid "Other problem" msgstr "בעיה אחרת" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "אלץ ניתוק" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr ".זה ישלח דוא\"ל בדיקה לחשבונך" #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "הראה יומן אירועים" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "בחן דוא\"ל" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "רושם ביומן" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "שגיאות/אזהרות" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ מידע" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ ניפוי תקלים" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "חיבורים" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "אזהרות אחרונות" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "נקה" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "בטל חסימה" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "מזהי מאמר" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "ערכת קבצים" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "מתי" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "סוג" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "מאופשר" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "לוח מחוונים" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "!חיבור נכשל" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "מקומית IPv4 כתובת" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "ציבורית IPv4 כתובת" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "IPv6 כתובת" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "DNS שם שרת / חיפוש" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "דגם יע''ם" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "(Pystone) ביצועי מערכת" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "מהירות תיקיית הורדות" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "מהירות תיקיית שלמים" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "מהירות כתיבה" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr ".לא היה יכול לכתוב. בדוק שהספרייה ניתנת לכתיבה" #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "לחץ על הכפתור חזור על בחינה למטה כדי לקבוע" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "חזור על בחינה" #: sabnzbd/skintext.py msgid "Config File" msgstr "קובץ תצורה" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "מטמון בשימוש" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" ".SABnzbd זה יפעיל מחדש את
השתמש בזה כשאתה חושב שלתכנית יש בעית " "יציבות.
הורדה תושהה לפני ההפעלה מחדש ותומשך לאחר מכן." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "
אם אימות מאופשר, תצטרך להיכנס שוב." #: sabnzbd/skintext.py msgid "Advanced" msgstr "מתקדם" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" ".ישנן עבודות יתומות בתיקיית ההורדות
.אתה יכול לבחור למחוק אותן (כולל " "קבצים) או לשלוח אותן חזרה לתור" #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "ויעשה בניה מחדש מלאה של SABnzbd כפתור התיקון יפעיל מחדש את
.תוכן התור, " "תוך שימור קבצים שהורדו כבר. זה ישנה את סדר התור" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "שינויים לא נשמרו, ויאבדו." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr ".מופעל מחדש, השיח יפוג SABnzbd שלך משתנה או IP-כאשר כתובת ה" #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "zip אפשר חילוץ" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "7zip אפשר" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "Par2 מרובה-ליבות" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" ".יוצפנו, אולם, מתן תוקף לזהות שרת ע\"י שימוש באישוריו הוא בלתי אפשרי HTTPS " "אל שרתי חדשות ואתרי SABnzbd-מ SSL חיבורים מאובטחים\r\n" ".מקומיים עדכניים דרושים CA ומעלה ואישורי OpenSSL 1.0.2 ,פייתון 2.7.9 ומעלה" #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" ".מרובה-ליבות, הוא זמין עבור פלטפורמות רבות Par2 האץ תיקונים ע\"י התקנת" #: sabnzbd/skintext.py msgid "Version" msgstr "גרסה" #: sabnzbd/skintext.py msgid "Uptime" msgstr "זמן פעולה" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "גיבוי" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "!קרא את עזרת וויקי על זה" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "מפעיל מחדש את SABnzbd..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "!SABnzbd שינויים ידרשו הפעלה מחדש של" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "SABnzbd שרת רשת" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "SABnzbd מארח" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr ".צריך להאזין אליו SABnzbd-מארח ש" #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "SABnzbd פתחת" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr ".צריך להאזין אליה SABnzbd-פתחה ש" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "ממשק רשת" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr ".בחר עור" #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "SABnzbd שם משתמש" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "שם משתמש רשותי של אימות" #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "SABnzbd סיסמת" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "סיסמת אימות רשותית" #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" ".SABnzbd חשופים לאינטרנט, ההגדרות הנוכחיות שלך מאפשרות גישה חיצונית מלאה אל " "ממשק SABnzbd אם המארח או הפתחה של" #: sabnzbd/skintext.py msgid "Security" msgstr "אבטחה" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "HTTPS אפשר" #: sabnzbd/skintext.py msgid "not installed" msgstr "לא מותקן" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr ".HTTPS אפשר מתן גישה אל הממשק מכתובת" #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "HTTPS פתחת" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr ".HTTPS אם ריק, הפתחה התקנית תאזין רק אל" #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "HTTPS אישור" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr ".HTTPS שם קובץ או נתיב אל אישור" #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "!SABnzbd חולל אישור ומפתח חדשים חתומים-עצמית. דורש הפעלה מחדש של" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "HTTPS מפתח" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr ".HTTPS שם קובץ או נתיב אל מפתח" #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "HTTPS אישורי שרשרת" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr ".HTTPS שם קובץ או נתיב אל שרשרת" #: sabnzbd/skintext.py msgid "Tuning" msgstr "כוונון" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "RSS מרווח בדיקת" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "!מרווח בדיקה (בדקות, לפחות 15). אינו פעיל כשאתה משתמש במתזמן" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "מהירות קו מרבית" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "אחוז של מהירות קו" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "להשתמש, לדוגמה 50 SABnzbd איזה אחוז ממהירות הקו צריך" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "מגבלת מטמון מאמרים" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" ".הטמן מאמרים בזיכרון כדי להפחית גישת דיסק
\"בבתים, עקוב באופן רשותי " "אחר ק,מ,ג'. לדוגמה: \"64מ\" או \"128מ" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "רשימת ניקוי" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" ".רשימת סיומות של קבצים שצריכים להימחק לאחר הורדה
nfo, sfv או " "nfo :לדוגמה" #: sabnzbd/skintext.py msgid "History Retention" msgstr "שימור היסטוריה" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" ".מחק באופן אוטומטי עבודות שלמות מההיסטוריה. שים לב ששימור כפול ומספר כלים " "חיצוניים מסתמכים על מידע היסטוריה" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "שמור את כל העבודות" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "שמור מספר מרבי של עבודות שלמות" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "שמור מספר ימים מרבי של עבודות שלמות" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "אל תשמור עבודות שלמות כלשהן" #: sabnzbd/skintext.py msgid "Jobs" msgstr "עבודות" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "שמור שינויים" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "שחזר ברירות מחדל" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "אפס" #: sabnzbd/skintext.py msgid "Language" msgstr "שפה" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr ".בחר שפת ממשק רשת" #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" "!לעברית SABnzbd עזור לנו לתרגם את
הוסף מלל לא מתורגם או שפר תרגומים " "קיימים כאן:" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr ".SABnzbd מפתח זה יתן לתכניות צד שלישי גישה מלאה אל" #: sabnzbd/skintext.py msgid "NZB Key" msgstr "NZB מפתח" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr ".SABnzbd אל NZB מפתח זה יתיר לתכניות צד שלישי להוסיף קבצי" #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "חולל מפתח חדש" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "API של מפתח QR קוד" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "רשימה של טווחי רשת מקומית" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr ".(\"כל כתובות הרשת המקומית מתחילות במקדמים אלו (לעיתים \"192.168.1" #: sabnzbd/skintext.py msgid "External internet access" msgstr "גישת אינטרנט חיצונית" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" ".אתה יכול לקבוע זכויות גישה עבור מערכות מחוץ לרשת המקומית שלך. דורש שרשימה " "של טווחי רשת מקומית תהיה מוגדרת" #: sabnzbd/skintext.py msgid "No access" msgstr "אין גישה" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "NZB הוסף קבצי " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "(ללא תצורה) API" #: sabnzbd/skintext.py msgid "Full API" msgstr "API מלא" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "ממשק רשת מלא" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "רק גישה חיצונית דורשת כניסה" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "הערה: תיקיות יווצרו באופן אוטומטי בעת שמירה. אתה יכול להשתמש " "בנתיבים מוחלטים כדי לשמור מחוץ לתיקיות ברירת המחדל" #: sabnzbd/skintext.py msgid "User Folders" msgstr "תיקיות משתמש" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "עיין" #: sabnzbd/skintext.py msgid "In" msgstr "ב" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "תיקיית הורדות זמניות" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" ".מיקום לאחסון הורדות בלתי מעובדות
.ניתן לשינוי כאשר התור ריק" #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "שטח פנוי מזערי עבור תיקיית הורדות זמניות" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" ".השהה באופן אוטומטי כששטח פנוי הוא מתחת לערך זה
\"בבתים, עקוב באופן " "רשותי אחר ק,מ,ג',ט. לדוגמה: \"800מ\" או \"8ג" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "תיקיית הורדות שלמות" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" ".מיקום לאחסון הורדות שהסתיימו, מעבודות במלואן
.ניתן להשתלט ע\"י " "מדורים מוגדרים ע\"י משתמש" #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "הרשאות עבור הורדות שלמות" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" ".קבע דפוס הרשאות עבור קבצים ותיקיות שלמים
בסימון אוקטלי. לדוגמה: 755 " "או 777" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "תיקייה מושגחת" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" ".nzb תיקייה לניטור אחר קבצי
.nzb אחר קבצי tar.gz-ו rar, zip סורק גם " "ארכיוני" #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "מהירות סריקה של תיקייה מושגחת" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr ".nzb מספר שניות בין סריקות עבור קבצי" #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "תיקיית תסריטים" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr ".תיקייה המכילה תסריטי משתמש" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "תיקיית תבניות דוא\"ל" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr ".תיקייה המכילה תבניות דוא\"ל מוגדרות ע\"י משתמש" #: sabnzbd/skintext.py msgid "Password file" msgstr "קובץ סיסמה" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr ".מוצפנים RAR קובץ המכיל את כל הסיסמאות שינוסו על קבצי" #: sabnzbd/skintext.py msgid "System Folders" msgstr "תיקיות מערכת" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "תיקייה מינהלית" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" ".מיקום עבור מסד-נתונים היסטוריה ומנהלן תור
.ניתן לשינוי רק כאשר התור " "ריק" #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "!SABnzbd נתונים לא יועברו. דורש הפעלה מחדש של" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "תיקיית יומן" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" ".SABnzbd מיקום של קבצי יומן עבור
!SABnzbd דורש הפעלה מחדש של" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr ".nzb תיקיית גיבוי" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr ".יאוחסנו .nzb מיקום שבו קבצי" #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "תיקיית יסוד ברירת מחדל" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "par2 הורד את כל קבצי" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr ".בעת הצורך par2 זה מונע הרצות תיקון מרובות ע\"י הורדת כל קבצי" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "אפשר פריקה נסיגתית" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr ".בתוך ארכיונים (rar, zip, 7z) פרוק ארכיונים" #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "התעלם מתיקיות כלשהן בתוך ארכיונים" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr ".כל הקבצים יעברו לתוך תיקייה יחידה" #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "השג מאמרים רק עבור ראש התור" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" ".אפשר עבור פחות שימוש בזיכרון. השבת כדי למנוע מעבודות איטיות לחסום את התור" #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "בצע בתר-עיבוד רק על עבודות שוודאו" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr ".PAR2-בצע בתר-עיבוד רק בעבודות שעברו את כל בדיקות ה" #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "מוצפן מורד RAR פעולה כאשר קובץ" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr ".במקרה של \"השהיה\", תצטרך לקבוע סיסמה ולהמשיך את העבודה" #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "גלה הורדות כפולות" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" "(.nzb זהים (על סמך פריטים בהיסטוריה שלך או קבצים בתיקיית גיבויים של NZB גלה " "קבצי" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "גלה פרקים כפולים בסדרות" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" "(גלה פרקים זהים בסדרות (על סמך \"שם/עונה/פרק\" של פריטים בהיסטוריה שלך" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "התר שחרורים תקינים" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" ".מתגלים בשם ההורדה REPACK או PROPER, REAL עקוף גילוי כפילויות סדרה אם" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "השלך" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "הכשל עבודה (העבר להיסטוריה)" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "הצמד תג לעבודה" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "בטל" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "פעולה כאשר סיומת בלתי רצויה מתגלה" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "RAR פעולה כאשר סיומת בלתי רצויה מתגלה בקבצי" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "סיומות בלתי רצויות" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "exe, com או exe :רשום את כל הסיומות הבלתי רצויות. לדוגמה" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "SFV אפשר בדיקות מבוססות" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr ".SFV בצע וידוא נוסף המבוסס על קבצי" #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "תסריט משתמש יכול לסמן בדגל עבודה כנכשלה" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" ".כאשר תסריט המשתמש מחזיר קוד יציאה בלתי-אפסי, העבודה תסומן בדגל כנכשלה" #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "חלופי NZB בכישלון, נסה" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr ".חלופי כאשר הורדה נכשלת NZB מספר שרתים מספקים" #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "השתמש בתגים ממדדן" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" ".בעת מיון, השתמש בתגים ממדדן עבור כותרת, עונה, פרק וכדומה\r\n" ".NZB-אחרת כל מתן השמות נגזר משם ה" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "אפשר שינוי שם תיקייה" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" ".השתמש בשמות זמניים במהלך בתר-עיבוד. השבת כאשר המערכת שלך אינה מתמודדת עם זה " "כראוי" #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "תסריט משתמש של קדם-תור" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr ".נכנס לתור NZB-בשימוש לפני ש" #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "נוספים PAR2 משתני" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Nice משתני" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "IONice משתני" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "התנתק בתור ריק" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr ".כאשר התור ריק או מושהה Usenet התנתק משרת(י)" #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "מיין לפי גיל" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr ".(מיין פריטים באופן אוטומטי לפי גיל (ממוצע" #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" ".רשומות יושהו עד שהן לפחות בגיל זה. קביעת עדיפות עבודה אל אילוץ תדלג על " "העיכוב" #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "בדוק אחר שחרור חדש" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr ".חדש SABnzbd בדוק פעם בשבוע אחר שחרור" #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "גם שחרורי בחינה" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "החלף רווחים בשמות תיקיות" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr ".החלף רווחים בקווים תחתונים בשמות תיקיות" #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "החלף נקודות בשמות תיקיות" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr ".החלף נקודות ברווחים בשמות תיקיות" #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Windows עשה תואם" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr ".Windows עבור שרתים: וודא שהשמות תואמים עם" #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "הפעל דפדפן באתחול" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr ".SABnzbd הפעל את דפדפן ברירת המחדל בעת התחלת" #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "השהה הורדה במהלך בתר-עיבוד" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr ".משהה הורדה בתחילת בתר-עיבוד וממשיך בסיום" #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "התעלם מדוגמאות" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr ".(סנן החוצה קבצי דוגמית (לדוגמה דוגמיות וידאו" #: sabnzbd/skintext.py msgid "Delete after download" msgstr "מחק לאחר הורדה" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "HTTPS וידוא אישור" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr ".HTTPS-ע\"י שימוש ב RSS וודא אישורים בעת התחברות אל מדדנים ומקורות" #: sabnzbd/skintext.py msgid "Server" msgstr "שרת" #: sabnzbd/skintext.py msgid "Post processing" msgstr "בתר-עיבוד" #: sabnzbd/skintext.py msgid "Naming" msgstr "מתן שמות" #: sabnzbd/skintext.py msgid "Quota" msgstr "מיכסה" #: sabnzbd/skintext.py msgid "Indexing" msgstr "אחסון במדד" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "('כמה ניתן להוריד החודש (ק/מ/ג" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "יום איפוס" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "(באיזה יום של החודש או השבוע (1=יום שני) ספק האינטרנט שלך מאפס את המיכסה? " "(לא חובה עם שש:דד" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "המשך באופן אוטומטי" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "?האם ההורדה תמשיך לאחר שהמיכסה אופסה" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "תקופת מיכסה" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "?האם המיכסה מתאפסת כל יום, שבוע או חודש" #: sabnzbd/skintext.py msgid "Check before download" msgstr "בדוק לפני הורדה" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "(!נסה לחזות השלמה מוצלחת לפני הורדה ממשית (איטי יותר" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "SSL צפני" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr ".חלש יותר SSL הגבר ביצועים ע\"י אילוץ חוזק הצפנת" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "ניסיונות חוזרים מרביים" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "מספר מרבי של ניסיונות חוזרים לשרת" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "בטל עבודות שאינן יכולות להיות שלמות" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "כאשר במהלך הורדה מתבהר שיותר מדי נתונים חסרים, בטל את העבודה" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "אפשר מיזוג מדדן" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" "יכול לדווח למדדן במקרה שעבודה לא יכלה להישלם SABnzbd-מדדנים יכולים לספק מידע " "מידרג כאשר עבודה מתווספת ו" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "אפשר סינון" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr ".הורדה בהתאם לכללי הסינון" #: sabnzbd/skintext.py msgid "Abort If" msgstr "בטל אם" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "ולא השהה אם" #: sabnzbd/skintext.py msgid "Video rating" msgstr "מידרג וידאו" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "מידרג שמע" #: sabnzbd/skintext.py msgid "Spam" msgstr "זבל" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "מאושר" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "יותר אגודלים למטה מאשר למעלה" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "מילות מפתח של כותרת" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "רשימה מופרדת בפסיקים" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "איזון-עומס של שרת" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "מנע איזון-עומס" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "התר איזון-עומס" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "IPv6 התר איזון-עומס עם ייעול עבור" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "אחת IPv4/IPv6 שימושי אם לשרת חדשות יש יותר מכתובת" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "הוסף שרת" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "תיאור שרת" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "פתחה" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "שם משתמש" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "סיסמה" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "פסק זמן" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "זמן שימור" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "חיבור מאובטח לשרת" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "וידוא אישור" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" "מאופשר, וודא את זהות השרת ע\"י שימוש באישוריו. קפדני: וודא ואכוף שם מארח " "תואם SSL מזערי: כאשר" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "מושבת" #: sabnzbd/skintext.py msgid "Minimal" msgstr "מזערי" #: sabnzbd/skintext.py msgid "Strict" msgstr "קפדני" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 הוא העדיפות הגבוהה ביותר, 100 הוא העדיפות הנמוכה ביותר" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "רשותי" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "עבור שרתים בלתי מהימנים, ייתקל בהתעלמות במקרה של כישלונות" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "אפשר" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "הסר שרת" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "בחן שרת" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "נקה מונים" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "...בוחן פרטי שרת" #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "רוחב פס" #: sabnzbd/skintext.py msgid "Send Group" msgstr "שלח קבוצה" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr ".פקודת שלח קבוצה לפני בקשת מאמרים" #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr ".השתמש רק בשרת זה עבור מדורים אלו" #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" ".לאף אחד מהשרתים המאופשרים אין את המדור 'ברירת מחדל' כנבחר. עבודות בתור " "שאינן מוקצאות לאחד ממדורי השרת לא יורדו" #: sabnzbd/skintext.py msgid "Personal notes" msgstr "הערות אישיות" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "הוסף תזמון" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "תזמונים נוכחיים" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" ".תיבת הסימון ליד שם ההזנה צריכה להיות מסומנת כדי שההזנה תהיה מאופשרת ותסומן " "באופן אוטומטי עבור פריטים חדשים
.\"אלא אם תלחץ \"אלץ הורדה RSS-כאשר " "הזנה מתווספת, היא תאסוף רק פריטים חדשים ולא שום דבר שנמצא כבר בהזנת ה" #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "הפרד כתובות רבות ע\"י פסיק" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "קרא הזנה" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "אלץ הורדה" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "מסנן" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "קבל" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "סרב" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "דורש" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "RequiresCat" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "לפחות" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "לכל היותר" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "SxxEyy-מ" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "Show SxxEyy-מ" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "תואם" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "בלתי תואם" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "הוּרד" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "קרא את כל ההזנות כעת" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "התראת דוא\"ל בעת השלמת עבודה" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "אף פעם" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "תמיד" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "שגיאה בלבד" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "התראות דיסק מלא" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr ".מושהה SABnzbd-שלח דוא\"ל כשהדיסק מלא ו" #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "RSS התראות שליחת" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr ".מוסיפה עבודות לתור RSS שלח דוא\"ל כאשר הזנת" #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "SMTP שרת" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr ".קבע את השרת של ספק האינטרנט שלך עבור דוא\"ל יוצא" #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "מקבל דוא\"ל" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr ".כתובת דוא\"ל לשלוח אליה את הדוא\"ל" #: sabnzbd/skintext.py msgid "Email Sender" msgstr "שולח דוא\"ל" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "?מי עלינו לומר ששלח את הדוא\"ל" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "שם משתמש רשותי של חשבון" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr ".עבור דוא\"ל מאומת, שם חשבון" #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "סיסמת חשבון רשותית" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr ".עבור דוא\"ל מאומת, סיסמה" #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Growl אפשר" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Growl שלח התראות אל" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "מרוחק (מארח:פתחה) Growl השתמש רק עבור שרת" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "סיסמת שרת" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "שרת Growl סיסמה רשותית עבור" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "NotifyOSD אפשר" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "NotifyOSD שלח התראות אל" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "מרכז ההתראות" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "שלח התראות אל מרכז ההתראות" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Windows אפשר התראות" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Windows התראות" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Prowl אפשר התראות" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Prowl דורש חשבון" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "Prowl עבור API מפתח" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "(דרוש) Prowl אישי עבור API מפתח" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Pushover אפשר התראות" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Pushover דורש חשבון" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "אסימון יישום" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "(אסימון יישום (דרוש" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "מפתח משתמש" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "מפתח משתמש (דרוש)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "התקן(ים)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "התקנים אליהם הודעה תישלח" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "ניסיון חוזר חרום" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "באיזו תדירות (בשניות) אותה ההתראה תישלח" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "תפוגת חרום" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "כמה שניות ההתראה שלך תמשיך להיות מנוסה שוב" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Pushbullet אפשר התראות" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Pushbullet דורש חשבון" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "אישי API מפתח" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "האישי שלך (דרוש) Pushbullet API מפתח" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "התקן" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "התקן אליו הודעה תישלח" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "תסריט התראות" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "אפשר תסריט התראות" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "מבצע תסריט מותאם אישית" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "?איזה תסריט עלינו לבצע עבור התראות" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" "ינסה להתאים למדורים המוגדרים למטה. בנוסף, אתה יכול להוסיף תנאים אל " "\"מדורים/קבוצות של מדדן\" כדי להתאים עוד מדורים. השתמש בפסיקים כדי SABnzbd " "אשר NZB-מדדנים יכולים לספק מדור בתוך ה\r\n" ".להפריד תנאים. תווים כללים נתמכים בתנאים
.עוד מידע יכול להימצא בוויקי" #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr ".סיום הנתיב עם כוכבית * תמנע יצירת תיקיות עבודה" #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "תיקיות קרובות משפחה מבוססות על" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "תיקייה/נתיב" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "מדורים / קבוצות של מדדן" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "מיון סדרות" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "אפשר מיון טלוויזיה" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "מפתח דפוס" #: sabnzbd/skintext.py msgid "Clear" msgstr "נקה" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "החל מסננים" #: sabnzbd/skintext.py msgid "Presets" msgstr "קדם-קביעות" #: sabnzbd/skintext.py msgid "Example" msgstr "דוגמה" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "מיון סרטים" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "אפשר מיון סרטים" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "שמור הורדות רפויות בתיקיות נוספות" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "מדורים מושפעים" #: sabnzbd/skintext.py msgid "Meaning" msgstr "משמעות" #: sabnzbd/skintext.py msgid "Pattern" msgstr "דפוס" #: sabnzbd/skintext.py msgid "Result" msgstr "תוצאה" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 תיקיית עונה" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 תיקיית עונה" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 תיקיית פרק" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 תיקיית פרק" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "שם עבודה בתור שם קובץ" #: sabnzbd/skintext.py msgid "Title" msgstr "כותר" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "שם סרט" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "שם.סרט" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "שם_סרט" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "הראה שם" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "הראה.שם" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "הראה_שם" #: sabnzbd/skintext.py msgid "Season Number" msgstr "מספר עונה" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "מספר פרק" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "שם פרק" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "שם.פרק" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "שם_פרק" #: sabnzbd/skintext.py msgid "File Extension" msgstr "סיומת קובץ" #: sabnzbd/skintext.py msgid "Extension" msgstr "סיומת" #: sabnzbd/skintext.py msgid "Part Number" msgstr "מספר חלקי" #: sabnzbd/skintext.py msgid "Decade" msgstr "עשור" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "שם מקורי של קובץ" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "שם עבודה מקורי" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "רישיות קטנה" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEXT" #: sabnzbd/skintext.py msgid "text" msgstr "text" #: sabnzbd/skintext.py msgid "file" msgstr "קובץ" #: sabnzbd/skintext.py msgid "Sort String" msgstr "מיין מחרוזת" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "תווית מרובה חלקים" #: sabnzbd/skintext.py msgid "In folders" msgstr "בתיקיות" #: sabnzbd/skintext.py msgid "No folders" msgstr "אין תיקיות" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "מיון תאריכים" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "אפשר מיון תאריכים" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "הראה שם תיקייה" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "תיקיות שנה-חודש" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "תיקיות יומיות" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "רישיות-מותאמת" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "תוצאה מעובדת" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" ".אפשרויות הנמצאות בשימוש לעיתים רחוקות. עבור משמעותן והסברן, לחץ על כפתור " "העזרה ולך אל דף הוויקי
.אל תשנה אותן ללא בדיקת הוויקי תחילה, מאחר שלכמה " "מהן יש תופעות לוואי רציניות
.ערכי ברירת המחדל הם בין הסוגריים" #: sabnzbd/skintext.py msgid "Values" msgstr "ערכים" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "NZB ערוך פרטי" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "מחק" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "ראש" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "למעלה" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "למטה" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "תחתית" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "הכל" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "הפוך" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "שם קובץ" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "נושא" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "בחירה" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "השהה למשך 5 דקות" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "השהה למשך 15 דקות" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "השהה למשך 30 דקות" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "השהה למשך שעה" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "השהה למשך 3 שעות" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "השהה למשך 6 שעות" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "נותר" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "שטח פנוי" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "תיקייה זמנית" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "רב-תפעולים" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "כדי לבחור טווח shift החזק את מקש" #: sabnzbd/skintext.py msgid "Check all" msgstr "סמן הכל" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "SABnzbd הפעל מחדש את" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "אפשרויות מצב וממשק" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "!או גרור ושחרר קבצים בחלון" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "..SABnzbd אבד חיבור אל" #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "!המסך יעלם באופן אוטומטי SABnzbd במקרה של הפעלה מחדש של" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "אזהרה:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "משוך" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "קצב רענון" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "השתמש בקביעות ממשק עולמיות" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "מגבלת פריטי תור" #: sabnzbd/skintext.py msgid "History item limit" msgstr "מגבלת פריטי היסטוריה" #: sabnzbd/skintext.py msgid "Date format" msgstr "תסדיר תאריך" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "עמודת תור נוספת" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "עמודה נוספת של היסטוריה" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "דף" #: sabnzbd/skintext.py msgid "Loading" msgstr "טוען" #: sabnzbd/skintext.py msgid "articles" msgstr "מאמרים" #: sabnzbd/skintext.py msgid "Rename" msgstr "שנה שם" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "תיקון תור" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "הראה חיבורים פעילים" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "עבודות יתומות" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "שלח חזרה לתור" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "מחק הכל" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "נסה שוב הכל" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "מכתובת NZB משוך" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "NZB העלה" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "ציין באופן רשותי שם קובץ" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr ".nzb, .rar, .zip, .gz, .bz2 :תסדירים" #: sabnzbd/skintext.py msgid "Submit" msgstr "הגש" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "פתח כתובת של מידע" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "הוגש. תודה!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "לא נבחר שום דבר!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "הסר את כל הקבצים שנבחרו" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "הסתר/הראה קבצים שלמים" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "הצג יומן תסריטים" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "עדכון זמין!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" "!אחסון מקומי (עוגיות) מושבת בדפדפן שלך, קביעות ממשק יאבדו לאחר שתסגור את " "הדפדפן" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "!יש מספר מאפיינים (חדשים) שאתה עשוי לאהוב Glitter-ל" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "מותאם" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "פריסה צמומה" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "פריסה בלשוניות
(תור והיסטוריה נפרדים)" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "מהירות" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "אשר מחיקות תור" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "אשר מחיקות היסטוריה" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "(!כמה זמן או עד מתי תרצה להשהות? (באנגלית" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr ".סליחה, לא יכולנו לפרש את זה. נסה שוב" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "...השהה למשך" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "רענן" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" ".מוסרים באופן אוטומטי מהיומן ומהעותק הכלול של ההגדרות שלך API-כל שמות " "המשתמש, הסיסמאות ומפתחות ה" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "מיין לפי גיל החדש ביותר→הישן ביותר" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "מיין לפי גיל הישן ביותר→החדש ביותר" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "מיין לפי שם א→ת" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "מיין לפי שם ת→א" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "מיין לפי גודל הקטן ביותר→הגדול ביותר" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "מיין לפי גודל הגדול ביותר→הקטן ביותר" #: sabnzbd/skintext.py msgid "Uploading" msgstr "מעלה" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "מאלץ ניתוק" #: sabnzbd/skintext.py msgid "Removing job" msgstr "מסיר עבודה" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "מסיר עבודות" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "הקודם" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "הבא" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "?לטהר את ההיסטוריה" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "!יתפקד Plush-כדי ש JavaScript אתה חייב לאפשר" #: sabnzbd/skintext.py msgid "Options" msgstr "אפשרויות" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "?לכמה דקות להשהות" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "תפריט עליון" #: sabnzbd/skintext.py msgid "On Finish" msgstr "בסיום" #: sabnzbd/skintext.py msgid "Sort" msgstr "מיין" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "מיין לפי גיל (הישן ביותר→החדש ביותר)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "מיין לפי גיל (החדש ביותר→הישן ביותר)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "מיין לפי שם (א→ת)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "מיין לפי שם (ת→א)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "מיין לפי גודל (הקטן ביותר→הגדול ביותר)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "מיין לפי גודל (הגדול ביותר→הקטן ביותר)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "?לטהר את התור" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "לנסות שוב את כל העבודות הנכשלות בהיסטוריה?" #: sabnzbd/skintext.py msgid "Purge" msgstr "טהר" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "מהירות מרבית" #: sabnzbd/skintext.py msgid "Range" msgstr "טווח" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "החל לנבחרים" #: sabnzbd/skintext.py msgid "Everything" msgstr "הכל" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "קצב רענון" #: sabnzbd/skintext.py msgid "Container Width" msgstr "רוחב מכל" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "זה ימנע רענון תוכן כשסמן העכבר שלך מרחף מעל התור" #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "חסום רענונים בריחוף" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "העלה" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr ".nzb .rar .zip .gz, .bz2 :העלה" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "התקדמות" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "!אין מספיק שטח פנוי כדי להשלים הורדות" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "פנוי (זמני)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "מושבת" #: sabnzbd/skintext.py msgid "Downloads" msgstr "הורדות" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "מחק שלמים" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "למחוק את כל הפריטים הנכשלים מההיסטוריה?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "מחק נכשלים" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "לנסות שוב את העבודות הנכשלות?" #: sabnzbd/skintext.py msgid "Links" msgstr "קישורים" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "מראה %s עד %s מתוך %s תוצאות" #: sabnzbd/skintext.py msgid "No results" msgstr "אין תוצאות" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "מראה תוצאה אחת" #: sabnzbd/skintext.py msgid "First" msgstr "ראשון" #: sabnzbd/skintext.py msgid "Last" msgstr "אחרון" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "!דוא\"ל נשלח" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "!התראה נשלחה" #: sabnzbd/skintext.py msgid "Saving.." msgstr "שומר.." #: sabnzbd/skintext.py msgid "Saved" msgstr "נשמר" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "NZB עורר הוספת" #: sabnzbd/skintext.py msgid "DualView1" msgstr "תצוגה כפולה 1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "תצוגה כפולה 2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "?SABnzbd האם אתה בטוח שברצונך להפעיל מחדש את" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "הסתר אפשרויות עריכה" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "הראה אפשרויות עריכה" #: sabnzbd/skintext.py msgid "Edit" msgstr "ערוך" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "זמן שנותר" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "SABnzbd אשף התחלה זריזה של" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "SABnzbd גרסת" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "הקודם" #: sabnzbd/skintext.py msgid "Server Details" msgstr "פרטי שרת" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr ".העיקרי שלך usenet אנא הכנס את הפרטים של ספק" #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "מספר החיבורים המותרים ע\"י הספק שלך" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "לדוגמה 8 או 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr ".SSL בחר רק אם הספק שלך מתיר חיבורי" #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr ".לחץ כדי לבחון את הפרטים שהוכנסו" #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "לדוגמה" #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "!ההתקנה שלמה כעת" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr ".ירוץ כעת ברקע SABnzbd" #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr ".SABnzbd סגירה של חלונות/לשוניות כלשהם/כלשהן לא תסגור את" #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" ".כאשר הוא רץ ברקע SABnzbd מומלץ ללחוץ לחיצה ימנית וליצור סימנייה למיקום זה " "ולהשתמש בסימנייה זו כדי להשיג גישה אל" #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "עזרה נוספת יכולה להימצא ב" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "SABnzbd עבור אל" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "SABnzbd-צא מ" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "התחל אשף" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" ".גרסה 2 או (לבחירתך) כל גרסה שהיא מאוחרת יותר GNU מגיע בהחלט ללא אחריות. זו " "תוכנה חינמית, ואתה מוזמן להפיצה מחדש תחת תנאים מסוימים. היא ברשיון תחת רשיון " "ציבורי כללי של SABnzbd\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" ".תידרש לך גישה אל ספק. ספק שירותי האינטרנט שלך עשוי לספק לך גישה, אולם מומלץ " "ספק פרימיום usenet-על מנת להוריד מ" #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr ".%s אנו ממליצים לנסות את ?usenet אין לך ספק" #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "(%s) שגיאה בהשגת מידע טלוויזיה" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "%s אל %s:נכשל בשינוי שם" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "%s אל %s :נכשל בשינוי שם של קובץ דומה" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "שם השרת אינו פותר" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "גישה בלתי מורשת" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "קובץ לא על השרת" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "השרת לא היה יכול להשלים בקשה" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "תופס כתובות קרס" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "בלתי שמיש NZB קובץ" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "%s ;משיכת כתובת נכשלה" #~ msgid "WARNINGS" #~ msgstr "אזהרות" #~ msgid "Hide files" #~ msgstr "הסתר קבצים" #~ msgid "HTTPS Support" #~ msgstr "תמיכת HTTPS" #~ msgid "Skip" #~ msgstr "דלג" #~ msgid "folder" #~ msgstr "תיקייה" #~ msgid "OK" #~ msgstr "אישור" #~ msgid "Queued" #~ msgstr "בתור" #~ msgid "Email Test Result" #~ msgstr "תוצאת בחינת דוא\"ל" #~ msgid "Show files" #~ msgstr "הראה קבצים" #~ msgid "Enable MultiCore Par2" #~ msgstr "מרובה ליבות Par2 אפשר" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "החל ניסיונות חוזרים מרביים רק על שרתים רשותיים" #~ msgid "Only for optional servers" #~ msgstr "רק עבור שרתים רשותיים" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "החלף תווים בלתי חוקיים בשמות תיקיות" #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr ".(החלף תווים בלתי חוקיים בשמות תיקיות בשווי ערך (אחרת יימחקו" #~ msgid "Original Foldername" #~ msgstr "שם קובץ מקורי" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "אינה קיימת \"%s\" התיקייה" #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "בלתי תקפים, לא יכול לוודא או לתקן par2 קבצי" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "%s (%s -> %s)-ב CRC שגיאת" #~ msgid "Main packet not found..." #~ msgstr "...חפיסה ראשית לא נמצאה" #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr ".Vista על ZoneAlarm-סביר להניח שאתה משתמש ב
" #~ msgid "SQL Commit Failed, see log" #~ msgstr "נכשל, ראה יומן SQL חיוב" SABnzbd-2.3.2/po/main/nb.po0000644000000000000000000043734613217005051013443 0ustar 00000000000000# Norwegian Bokmal translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2017-09-03 14:07+0000\n" "Last-Translator: Steffen Bærø \n" "Language-Team: Norwegian Bokmal \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:31+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Kunne ikke starte webgrensesnittet" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "Kan ikke finne webmal: %s, prøver standardmal" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" "SABYenc deaktivert: Fant ikke korrekt versjon! (Fant v%s, forventet v%s)" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" "SABYenc modul... IKKE funnet! Forventet v%s - https://sabnzbd.org/sabyenc" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "_yenc-modul... IKKE funnet!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "par2-binærfil... IKKE funnet!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "Verifikasjon og reparasjon vil ikke være mulig." #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "MultiPar-binærfil... IKKE funnet!" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" "Din Unrar-versjon er %s, vi anbefaler versjon %s eller høyere.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "Nedlastinger vil ikke blir pakket ut." #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "unrar-binærfil... IKKE funnet!" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "unzip-binærfil... IKKE funnet!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "7za-binærfil... IKKE funnet!" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Husk at vertsnavnet 0.0.0.0 krever en IPv6-adresse for ekstern tilgang" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "HTTP og HTTPS-portene kan ikke være det samme" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" "SABnzbd ble startet med koding %s, dette burde være UTF-8. Forvent problemer " "med Unicode filer- og katalognavn i nedlastinger." #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "Deaktiverte HTTPS på grunn av manglende CERT- og KEY-filer." #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Kunne ikke starte webgrensesnittet: " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "Kan ikke nå SABHelper-tjenesten" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s startet" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Advarsel" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Feil" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "SABnzbd er nå avsluttet" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Du har ikke stilt inn vertsnavn." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "Ingen tilkoblinger er aktivert. Du må aktivere minst en tilkobling." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Passordet er skjult med ******, prøv igjen" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Ugyldige server-innstillinger" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "Tidsavbrudd: Prøv å aktivere SSL eller bruk en annen port." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Tidsavbrudd" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" "Ukjent SSL-protokoll: Prøv å deaktivere SSL eller koble til på en annen port." #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Ugyldig server-adresse." #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Server avbrøt undet innloggingssekvens" #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Server krever brukernavn og passord." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Tilkobling lyktes!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Godkjenning mislyktes, kontroller brukernavn og passord." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "For mange tilkoblinger, sett nedlasting på pause eller prøv igjen senere" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Kunne ikke koble til (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Signal %s mottatt, lagrer og avslutter..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Kritisk feil ved lagring av tilstand" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Forsøker å hente NZB fra %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Lagring av %s mislyktes" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Kan ikke lage midlertidig fil for %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Forsøker å sette status på ikke-eksisterende server %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Feil i tempfil.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Lasting av %s mislyktes" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Laster %s feilet med feilmelding %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Test varslingen" #: sabnzbd/api.py msgid " Resolving address" msgstr " Løs adresse" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Ingen" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Standard" #: sabnzbd/api.py msgid "unknown" msgstr "ukjent" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Kunne ikke lage regex for søkestreng: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "For lite diskplass, nedlasting satt på pause" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Disken er full! Pauser..." #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Diskfeil under opprettelse av fil %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Kritisk feil i Assembler" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Avbrutt, kryptering funnet" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "ADVARSEL: I \"%s\" uønsket filtype i RAR fil. Uønsket fil er %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "Uønsket forlenging finnes i rar fil %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Avbryt, uønsket forlenging oppdaget" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "ADVARSEL: Pauset jobb \"%s\" grunnet rangeringen (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "ADVARSEL: Avbrøt jobb \"%s\" grunnet rangering (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Avbrøt, rangeringsfilter var lik (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s mangler" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "video" #: sabnzbd/assembler.py msgid "audio" msgstr "lyd" #: sabnzbd/assembler.py msgid "spam" msgstr "søppel" #: sabnzbd/assembler.py msgid "passworded" msgstr "passordbeskyttet" #: sabnzbd/assembler.py msgid "downvoted" msgstr "nedstemt" #: sabnzbd/assembler.py msgid "keywords" msgstr "nøkkelord" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Kvote oppbrukt, setter nedlasting på pause" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s er ikke en godkjent e-post-adresse" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Krever server-adresse" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Kan ikke opprette %s mappe %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Kan ikke skrive til INI-fil %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Kan ikke sikkerhetskopiere fil %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Feil kodet passord %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s er ikke en korrekt oktal verdi" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "UNC-sti \"%s\" er ikke tillatt her" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Feil: Fillengde bør være kortere enn %s." #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Feil: Køen er ikke tom, kan ikke bytte mappe." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "Kan ikke skrive til historikkdatabase, sjekk filrettigheter" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "Skadet historikkdatabase, opprettet ny database" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "SQL-kommando mislyktes, se logg" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Kunne ikke stenge databasen, se logg" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Ugyldig scenen logging i historien for %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Dekoding av %s mislyktes" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Feilaktigt utformet yEnc artikkel i %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Ukjent feil oppstod under dekoding av %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "UUencode oppdaget, bare yEnc koding er støttet[%s]" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => mangler på alle servere, fjerner" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Ferdig" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "Utpakket %s filer/mapper på %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "Kan ikke lese %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Kunne ikke legge til %s, tar bort" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Feil ved fjerning av %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Kan ikke lese den overvåkede mappen %s" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Gjenopptar" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Pauset" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Du må sette maks båndbredde før du kan sette en båndbreddebegrensning" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Server %s vil bli ignorert i løpet av %s minutter" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Feilet å starte %s@%s grunnet: %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "For mange tilkoblinger til server %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Mistenkt kontodeling" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Kunne ikke logge inn på server %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Kan ikke koble til server %s [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "Kontaker %s@%s feilet, feilmelding=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Server %s krever brukernavn/passord" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Mistenker feil i nedlaster" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Starter avslutning av SABnzbd.." #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Kunne ikke koble til mailserver" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "Kunne ikke starte TLS-tilkobling" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "Serveren svarte ikke ordentlig til helo hilsen" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Autentisering mot mailserveren mislyktes" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Ingen passende autentiseringsmetode ble funnet" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "Ukjent godkjenningsfeil i e-postserveren" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Kunne ikke sende e-post" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Kunne ikke stenge e-post-tilkobling" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "E-post sendning lykkes" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Kan ikke sendes, mangler nødvendig data" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Kan ikke finne e-post-maler i %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Ingen mottaker oppgitt, e-post ikke sendt" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Ugyldig koding av e-post mal %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Ingen e-post-mal funnet" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd rapporterer at disken er full\n" "\n" "Hei,\n" "\n" "SABnzbd har stoppet all nedlasting da lagringsdisken nesten er full.\n" "Frigjør mer diskplass og gjenoppta nedlasting manuelt.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "Advarsel: LOCALHOST er tvetydig, bruk numerisk IP-adresse." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Serveradressen \"%s:%s\" er ikke gyldig." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "Bruker logget inn i webgrensesnitt" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "Bruker pålogget" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Mangler sesjonsnøkkel" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Feil: Krever sesjonsnøkkel" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Feil: Feil sesjonsnøkkel" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "API-nøkkel mangler, skriv inn API-nøkkelen fra Konfigurasjon->Generelt i " "ditt tredjepartsprogram:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "API-nøkkel er feil, bruk API-nøkkel fra Konfigurasjon->Generelt i ditt " "tredjepartsprogram:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Autentisering mangler, angi brukernavn/passord fra Konfigurasjon->Generelt i " "ditt tredjepartsprogram:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Prøv vår nye skin Glitter! Nytt og friskt design som er optimalisert for " "stasjonære og mobile enheter. Gå til Konfig -> Generelt for å endre ditt skin" #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "Mislykket påloggingsforsøk fra %s" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
SABnzbd er avsluttet.
Vent rundt 5 sekunder og klikk " "deretter på knappen under.

Last på " "nytt
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "RSS-kilde" #: sabnzbd/interface.py msgid "Daily" msgstr "Daglig" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "Mandag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Tirsdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Onsdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Torsdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Fredag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Lørdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Søndag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "av" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Udefinert server!" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Feil parameter" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Tilbake" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "FEIL:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Feil verdi for %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "d" #: sabnzbd/misc.py msgid "h" msgstr "h" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Kan ikke opprette mappe %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "%s mappe: %s tilgang mislyktes" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Opprettelse av (%s) mislyktes" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Kunne ikke flytte %s til %s" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Kunne ikke lage SSL-nøkkel eller sertifikat." #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Kunne ikke endre rettigheter på %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Kjører skript" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Etterbehandling ble avbrutt (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Skript" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Utpakking nestet for dypt [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Slår sammen filer" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Ufullstendig sekvens av oppdelte filer" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Filsammenslåing av %s mislyktes" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Feil \"%s\" under filsammenslåing" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Feil \"%s\" under kjøring av file_join på %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] Slår sammen %s filer" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Utpakking mislyktes, %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Feil \"%s\" under utpakking av RAR fil(er)" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Feil \"%s\" under kjøring av rar_unpack på %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Fjerning av %s mislyktes!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Prøver unrar med passord \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Utpakking mislyktes, arkivet krever passord" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Utpakker" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Utpakking" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Utpakking mislyktes, kunne ikke finne %s" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "FEIL: kunne ikke finne \"%s\"" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Utpakking mislyktes, CRC-feil" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "FEIL: CRC mislyktes i \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "Utpakking feilet, filen er for stor for filsystemet (FAT?)" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "FEIL: Filen er for stor for filsystemet (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "Utpakking mislyktes, skrivefeil eller er disken full?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "FEIL: skrive feil (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Utpakking feilet, stien er for lang" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "FEIL: sti er for lang (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Utpakking mislyktes, se logg" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "FEIL: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Ubrukelig RAR-fil" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s filer på %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Feil \"%s\" under kjøring av unzip() på %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Prøver 7zip med password \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "7ZIP set \"%s\" er ikke komplett, kan ikke pakke ut" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Kunne ikke pakke ut %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Hurtigkontrollerer" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Reparerer" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Hurtigkontroll OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Starter reparasjon" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "Par verifisering feilet på %s, mens hurtigsjekk var vellykket!" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Reparasjon mislyktes, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Feil %s under kjøring av par2_repair på %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Feil \"%s\" under kjøring av par2_repair på %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] PAR2 mottok feil kommandoer, undersøk brytere i Konfigurasjon->Brytere" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Verifiseing tok %s, alle filer er ok" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Verifisering tok %s, krever reparasjon" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "Henter %s blokker..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Henter" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "" "Mislykket reparasjon, finner ikke nødvendige reparasjonsblokker (%s mangler)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Reparerer" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Reparert på %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Harddisken er full" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Verifiserer" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Undersøker" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Denne serveren tillater ikke SSL på denne porten" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Oppstart/avsluttning" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "La til NZB-fil" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Etterbehandling startet" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Jobb fullført" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Jobb mislyktes" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Køen er ferdig" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Andre meldinger" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Ikke tilgjengelig" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Klarte ikke å sende Prowl melding" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Ukorrekt svar fra Pushover (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Klarte ikke å sende pushover-melding" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Ukorrekt svar fra Pushbullet (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Klarte ikke å sende pushbullet-melding" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "Klarte ikke å sende Windows melding" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "Gammel kø oppdaget. Bruk Status -> Reparer for å konvertere køen" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Feilaktig kø-fil funnet, kan ikke fortsette" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Lastingsfeil %s, feilaktig fil oppdaget" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "Klarte ikke restarte NZB etter forhåndssjekk (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB er lagt til i køen" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Ukjent koding" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Fil %s er tom, hopper over" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Kunne ikke importere %s filer fra %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Ufullstendig NZB-fil %s" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Feilaktig NZB fil %s, hopper over (årsak=%s, linje=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Tom NZB-fil %s" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Ignorerer duplikatfil \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Stanser duplikatfil \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Avbrutt, kan ikke fullføres" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "DUPLIKAT" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "KRYPTERT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "FOR STOR" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "UFULLSTENDIG" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "UØNSKET" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "FILTRERT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "VENT %s sek" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Hentet filer på %s med gjenomsnitts hastighet på %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Tid" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s artikler var korrupte" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s artikler manglet" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s artikler hadde ulike duplikater" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s artikler ble slettet" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Kunne ikke importere %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Advarsler" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Ledig" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Konfigurasjon" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Kø" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Slett kø" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Historikk" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Slett historikk" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Hastighetsbegrensning" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Stans midlertidig" #: sabnzbd/osxmenu.py msgid "min." msgstr "min." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Gjenoppta" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Sjekk overvåkingsmappe" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Les alle RSS-kanaler" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Ferdig mappe" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Ufullstendig mappe" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Feilsøking" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Starte på nytt" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Restart uten å logge inn" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Avslutte" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Kø (10 første)" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Tom" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Historikk (10 siste)" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Ny utgave er tilgjengelig" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Gå til guiden" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Avslutter..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Problem med" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd trenger en ledig TCP/IP-port for sin interne webserver.
\n" " Port %s på %s ble forsøkt brukt, men er utilgjengelig.
\n" " Enten er porten allerede i bruk av et annet program, eller så kjører " "SABnzbd fra før av.
\n" "
\n" " Start SABnzbd på nytt med et annet portnummer." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "Prøv et annet nummer hvis du får denne feilmeldingen på nytt.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd krever en gyldig adresse for sin interne webserver.
\n" " Du har spesifisert en ugyldig adresse.
\n" " Korrekte verdier er localhost og 0.0.0.0
\n" "
\n" " Vennligst start SABnzbd på ny med en gyldig adresse." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd oppdaget instillinger fra en annen SABnzbd-versjon
\n" " men kan ikke bruke disse.

\n" " Kanskje vil du fullføre nedlastingskøen i det gamle programmet " "først?

\n" " Etter det kan du starte dette programmet med \"--clean\"-" "parameteren.
\n" " Dette vil slette nedlastingskø og historie!
\n" " SABnzbd leste filen \"%s\"." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd kan ikke finne filene for webgrensesnittet i %s.
\n" " Vennligst installer programmet på nytt.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd oppdaget en kritisk feil:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd oppdaget at filen sqlite3.dll is mangler.

\n" " Enkelte antivirus-programmer fjerner denne filen.
\n" " Vennligst sjekk ditt antivirusprogram og forsøk å installer SABnzbd på " "nytt.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Trykk Start+R og skriv inn linjen (eksempel):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Åpne et terminalvindu og skriv inn linjen (eksempel):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Programmet startet ikke!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Kritisk feil" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "Kan ikke starte webserveren, ble sannsynlig vis ikke funnet" #: sabnzbd/panic.py msgid "Access denied" msgstr "Ingen tilgang" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Feil %s: Du må oppgi et gyldig brukernavn og passord." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "Nedlasting kan feile, kun %s av kravet på %s tilgjengelig" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Nedlastning feilet - Finnes ikke på din(e) server(e)" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Ingen etterbehandling, på grunn av misslykket verifisering" #: sabnzbd/postproc.py msgid "Moving" msgstr "Flytter" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "Sendte %s til køen" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Kunne ikke endre navn fra \"%s\" til \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Klarte ikke å flytte filer" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Kjør brukerskript %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "Kjørte i %s" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Skript-avsluttingskode er %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Mer" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Etterbehandling mislyktes for %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "se loggfil" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Nedlasting mislyktes" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Rensning av %s mislyktes" #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Kunne ikke fjerne arbeidsmappe (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Nedlasting ferdig" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Kan ikke opprette mappe %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Etterbehandling" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Ingen par2 deler" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Prøver SFV-verifisering" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Some files failed to verify against \"%s\"" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Verifisering med SFV-filer var vellykket" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "Passord" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Fjerning av %s mislyktes" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Dvalemodus feilet" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Kunne ikke sette systemet i ventemodus" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Feil under avslutting av systemet" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "Fant ikke indekser id (%s) for rangeringsfil." #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Tjeneradresse" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "API-nøkkel" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Feilaktig RSS-kilde beskrivelse \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Kunne ikke hente RSS-kilde fra %s: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Ugyldig autentisering for nyhetsstrøm %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "Serverside-feil (serverkode %s); kunne ikke hente %s på %s" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "Server %s bruker et usikkert HTTP sertifikat" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "RSS-kilde %s var tom" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Ukompatibel nyhetsstrøm" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Tom RSS post funnet (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Vis grensesnitt" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Åpne fullført mappe" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Avslutt" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Gjenstår" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Legg til NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Feil skjema %s ved %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Ukjent handling: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Skjema for ikke eksisterende server %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Nedlastning" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Slå sammen filer" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Kilde" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Servere" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Feil" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Mislyktes" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "Venter" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Reparerer..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Trekker ut..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Flytter..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Kjører skript..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Henter ektra blokk..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Hurtigkontroll..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Verifserer..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Laster ned" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Hyppighet" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Handling" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Argument" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Oppgave" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "Deaktiver server" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "Aktiver server" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Hastighetsgrense" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Pause Allt" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Pause etterbehandling" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Gjenoppta etterbehandling" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Les RSS-kilde" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Fjerne mislykkede jobber" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Fjern ferdige jobber" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Pause jobber med lav prioritet" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Pause jobber med normal prioritet" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Pause jobber med høy prioritet" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Gjenoppta jobber med lav prioritet" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Gjenoppta jobber med normal prioritet" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Gjenoppta jobber med høy prioritet" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Aktiver kvotebegrensninger" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Deaktiver kvotebegrensninger" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Av" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Veldig lav" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Moderer" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normal" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Høy" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Nødssituasjon" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Lav" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "MB" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "GB" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "time" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "timer" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "minutt" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "minutter" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "sekund" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "sekunder" #: sabnzbd/skintext.py msgid "day" msgstr "dag" #: sabnzbd/skintext.py msgid "days" msgstr "døgn" #: sabnzbd/skintext.py msgid "week" msgstr "uke" #: sabnzbd/skintext.py msgid "Month" msgstr "Måned" #: sabnzbd/skintext.py msgid "Year" msgstr "År" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Dag i måneden" #: sabnzbd/skintext.py msgid "This week" msgstr "Denne uken" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Denne måneden" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "I dag" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Totalt" #: sabnzbd/skintext.py msgid "on" msgstr "på" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parametere" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Python-versjon" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Startside" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "eller" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Adresse" #: sabnzbd/skintext.py msgid "Comment" msgstr "Kommentar" #: sabnzbd/skintext.py msgid "Send" msgstr "Send" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Avbryt" #: sabnzbd/skintext.py msgid "Other" msgstr "Andre" #: sabnzbd/skintext.py msgid "Report" msgstr "Rapport" #: sabnzbd/skintext.py msgid "Video" msgstr "Video" #: sabnzbd/skintext.py msgid "Audio" msgstr "Lyd" #: sabnzbd/skintext.py msgid "Not used" msgstr "Ubrukt" #: sabnzbd/skintext.py msgid "or less" msgstr "eller mindre" #: sabnzbd/skintext.py msgid "Log in" msgstr "Logg på" #: sabnzbd/skintext.py msgid "Log out" msgstr "Logg av" #: sabnzbd/skintext.py msgid "Remember me" msgstr "Husk meg" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "Det automatiske usenet nedlastnings verktøyet" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Lagre" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Er du sikker?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Slett alle nedlastninger?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Hjem" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Konfigurasjon" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Status" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Hjelp" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Forum" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Generelt" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Mapper" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Svitsjer" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Nedlastingsplan" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Varsler" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "E-Post" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Kategorier" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Sortering" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Spesiell" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Søk" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Midlertidig nedlastingsmappe" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "Pause" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "Lagret %s artikler (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Systemlast" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Ny utgave %s tilgjengelig" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Er sikker på at du vil slå av SABnzbd?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Legg-til" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Legg til fil" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Kategori" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Bearbeidinger" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Prioritet" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Reparere" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Pakker opp" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Fjern" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "P" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "T" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Tving" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Stopp" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "Når køen er ferdig" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Slå av PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "Ventemodus PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Dvalemodus PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Avslutning av SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Hastighetsgrense" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Pause for" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Sortering" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Navn" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "Tid igjen" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "Alder" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Fjern" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Prøv igjen" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Hendelser" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Skripts" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Slett alt fra køen?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Slett NZB-filer" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Slett NZB & tilhørende filer" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Prøv alle mislykkede jobber på nytt" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Fjern NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Fjern NZB & slett filer" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "av" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Manglende artikler" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Gjenværende kvote" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "manuelt" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Nullstill kvote nå" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Slett alle fullførte nedlastinger fra historie?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Skjul detaljer" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Vis detaljer" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Vis Mislykkede" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Vis alle" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Størrelse" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Fjern Mislykkede NZBer" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Fjern Mislykkede NZBer & Slett Filer" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Fjern Ferdige NZBer" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "Alternativ tilleggs NZB" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Snarvei" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Prøv alle mislykkede på nytt" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Prøv alle på nytt" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus/spam" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "" "Det du prøver å laste ned er eldre enn hva usenet leverandøren din har lagret" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Andre problemer" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Tving frakobling" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Dette vil sende en test e-post til din konto." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Logg" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Test E-post" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Logging" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Feil/Advarsel" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ Info" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ Feilsøking" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Tilkoblinger" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Seneste Advarsler" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "slette" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Fjern blokkering" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Artikkel-id" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Filsett" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Når" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Type" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Aktivert" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Kontrollpanel" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Tilkobling mislykket!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Lokal IPv4-adresse" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Offentlig IPv4 adresse" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "IPv6-adresse" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Navnserver / DNS oppslag" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "CPU-modell" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "Systemytelse (Pystone)" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Nedlastingsmappe-hastighet" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Ferdig mappe-hastighet" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Skrivehastighet" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "Kunne ikke skrive. Sjekk skrive rettigheter til mappen." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Klikk på gjenta test knappen under for å bestemme." #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Gjenta test" #: sabnzbd/skintext.py msgid "Config File" msgstr "Konfig fil" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Brukt hurtigbuffer" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Dette vil starte om SABnzbd.
Brukes når du tror programmet er " "ustabilt.
Nedlastning vil bli satt på pause før omstarten og gjenoppta " "etterpå." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" #: sabnzbd/skintext.py msgid "Advanced" msgstr "" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Det finnes foreldreløse jobber i nedlastningsmappen.
Du kan velge å " "slette disse (filene vil også bli slettet) eller sende dem tilbake i " "nedlastningskøen." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Endringer som ikke er lagret vil gå tapt." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Aktiver Unzip" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "Aktiver 7zip" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" #: sabnzbd/skintext.py msgid "Version" msgstr "Versjon" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Oppetid" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Sikkerhetskopi" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Les Wiki Help fer dette!" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Starter SABnzbd på nytt..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Endringer krever omstart av SABnzbd!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "SABnzbd Webbserver" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "SABnzbd Adresse" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Adressen som SABnzbd skal bruke." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "SABnzbd-port" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Porten som SABnzbd skal bruke." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Webgrensesnitt" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Velg et skall." #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "SABnzbd Brukernavn" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Kan velge autentiserings brukernavn." #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "SABnzbd Passord" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Kan velge autentiserings passord." #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "HTTPS Aktivere" #: sabnzbd/skintext.py msgid "not installed" msgstr "(ikke installert)" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Aktiverer tilgangen til webgrensesnittet med HTTPS adresse." #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "HTTPS-port" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Om tom, så vil standardporten bare lytte til HTTPS" #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "HTTPS Sertifikat" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Filnavn eller søkesti til HTTPS Sertifikat." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "HTTPS Nyckel" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Filnavn eller søkesti til HTTPS Nøkkel." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "HTTPS-lenke sertificater" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Filnavn eller sti til HTTPS-lenke" #: sabnzbd/skintext.py msgid "Tuning" msgstr "Justeringer" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "RSS Oppdateringsintervall" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Sjekk intervall (i minutter, minst 15). Ikke aktiv når du bruker " "nedlastingsplan!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Maks linje-hastighet" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Prosent av linjehastighet" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "Hvor mange prosent av linjehastigheten skal SABnzbd bruke, feks. 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Cachestørrelse for artikkler" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Lagrer artikler i minnet for å redusere diskaktivitet.
I bytes, " "fulgt av K,M,G. For eksempel: \"64M\" eller \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Rens liste" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Liste over filtyper som skal slettes etter nedlasting.
For eksempel: " "nfo eller nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Lagre endringer" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Nullstill" #: sabnzbd/skintext.py msgid "Language" msgstr "Språk" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Velg språket til Webgrensesnittet." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "Denne nøkkelen vil gi tredjepartsprogrammer full tilgang til SABnzbd" #: sabnzbd/skintext.py msgid "NZB Key" msgstr "NZB-nøkkel" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "Denne nøkkelen vil gi tredjepartsprogrammer lov til å legge til NZBer til " "SABnzbd" #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Generer Ny Nøkkel" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "API-nøkkel QR-kode" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Liste over lokale nettverksområder" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Alle lokale nettverksadresser starter med disse prefix (ofte \"192.168.1.\")" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Ekstern internettilgang" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" #: sabnzbd/skintext.py msgid "No access" msgstr "Ingen tilgang" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Legg til NZB filer " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (Ingen konfigurasjon)" #: sabnzbd/skintext.py msgid "Full API" msgstr "Full API" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Fullt webgrensesnitt" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "OBS: Mapper kommer til å bli opprettet automatiskt når du Lagrer. " "Du må angi korrekte søkestier til din mapper for å kunne lagre utenfor " "standardmappene." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Brukermapper" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Bla gjennom" #: sabnzbd/skintext.py msgid "In" msgstr "Hvor:" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Midlertidig nedlastingsmappe" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Plass for å lagre ikke bearbeidede nedlastinger.
Kan kun endres når " "køen er tom." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Minimal fri plass for midlertidig nedlastingsmappe" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Auto-pause når fri plass er nærme grensen.
I bytes, fulgt av " "K,M,G,T. For eksempel: \"800M\" eller \"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Ferdig nedlastingsmappe" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Plass for å lagre bearbeidede og ferdige nedlastinger.
Kan " "overstyres av brukerdefinerte kategorier." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Rettigheter for ferdige nedlastinger" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Sett rettigheter for ferdige filer og mapper.
Bruk tall. For " "eksempel: \"755\" or \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Overvåket Mappe" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Mappe som automatiskt søkes igjennom etter .nzb filer.
Skanner også " "igjennom .zip .rar og .tar.gz arkiver etter .nzb filer." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Skanningsintervall for Overvåkede mappar" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Sekunder mellom skanninger for .nzb filer." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Mappe for E-post maler" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Mappe som inneholder brukerdefinerte e-post maler." #: sabnzbd/skintext.py msgid "Password file" msgstr "Passordfil" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Fil som inneholder alle passordene som skal forsøkes på krypterte RAR filer." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Systemmapper" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Administrativ Mappe" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Lokasjon for køadmin og historikkdatabase.
Kan bare endres når køen " "er tom." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "Data vil ikke bli flyttet. Krever SABnzbd restart!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Loggmappe" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Plass for lagrede loggfiler fran SABnzbd.
Krever omstart av " "SABnzbd!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr ".nzb Reservemappe" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Plass der .nzb filer lagres." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Standard base filsti" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Last ned alle par2 filer" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Aktiver rekursiv utpakking" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Pakk ut arkiver (rar, zip, 7z) inne i arkiver" #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Ignorer alle mapper inne i arkiver" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Alle filer vil bli lagt til samme mappe" #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Bara artiklene fra begynnelsen av køen" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Aktiveres for mindre minneforbruk. Deaktiver for å forhindre langsom jobb da " "køen blokkeres." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Etterbehandle kun verifiserte nedlastinger" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "Etterbehandle kun nedlastinger som har passert PAR2 kontrollen." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Reaksjon når kryptert RAR fil lastes ned" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "I tilfelle \"Pause\", så trenger du å sette et passord og gjenoppta jobben." #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Oppdag duplikatnedlastinger" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Oppdag duplikat episoder i serie" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Forkast" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Avbryt" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Handling når uønsket filtype oppdaget" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "Handling når uønsket filtype blir oppdaget i RAR filer." #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Uønsket filtyper" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Skriv alle uønskende filtyper. For eksempel: exe eller exe, " "com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Aktiver SFV-baserte sjekker" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Utfør ekstra verifisering basert på SFV filer" #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Brukerskript kan flagge jobb som mislykket" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Når brukerskriptet returnerer en ikke-null exit kode, vil jobben bli flagget " "som mislykket." #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "Når den feiler, prøv alternativ NZB-fil" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "Noen servere vil gi en alternativ NZB når en nedlasting mislykkes." #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Aktiver omdøping av mappe" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Bruk midlertidige navn under postprosessering. Deaktiver når systemet ditt " "ikke håndtere dette skikkelig." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Før-kø bruker skript" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Brukes før en NZB blir lagt til kø" #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Ekstra PAR2 parametere" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Nice parametere" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "IONice parametere" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Koble fra når køen er tom" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "Kople fra usenet serverne når køen er tom eller pauset." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Sortere etter alder" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Sortere automatisk etter(midt) alder." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Se etter ny utgave" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Se etter ny utgave av SABnzbd hver uke." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "Også nye utgivelser" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Erstatt mellomrom i mappenavn" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Erstatt mellomrom med understrek i mappenavn." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Erstatt punktum i mappenavn" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Erstatt punktum med mellomrom i mappenavn" #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Gjør Windows-kompatibel" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "For servere: sørg for at navn er kompatibel med Windows." #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Starter webleseren ved oppstart" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Starter standard webleser når SABnzbd starter." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Pause nedlasting under etterbehandling" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Pauser nedlasting når etterbehandling begynner og gjenopptar nedlasting når " "etterbehandling er ferdig." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Ignorer Sample-filer" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Filtrere ut sample-filer (ex. video samplinger)." #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Fjern etter nedlasting" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" #: sabnzbd/skintext.py msgid "Server" msgstr "Server" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Postprosessering" #: sabnzbd/skintext.py msgid "Naming" msgstr "Filnavn" #: sabnzbd/skintext.py msgid "Quota" msgstr "Kvote" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indeksering" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Hvor mye can lastes ned denne måneden (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Nullstillingsdag" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "På hvilken dag i måneden eller uken (1=mandag) resetter til nettilbyder " "kvoten? (Valgfritt med tt:mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Gjenoppta automatisk" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "Skal nedlasting starte på nytt etter at kvoten er resatt?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Kvoteperiode" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "Blirkvoten resatt hver dag, uke, eller måned?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Sjekk før nedlasting" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Prøve å beregne om ferdigstillelse er mulig før selve nedlastingen (tregere!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Maksimum antall forsøk" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Maksimum antall forsøk per server" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Avbryt jobber som ikke kan fullføres" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Avbryt jobben om det blir klart under nedlasting at for mye data mangler" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Aktiver filtrering" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Bruk nedlastinghandlinger ifølge filtreringsreglene." #: sabnzbd/skintext.py msgid "Abort If" msgstr "Avbryt Hvis" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Ellers Pause Hvis" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Video-rangering" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Audio-rangering" #: sabnzbd/skintext.py msgid "Spam" msgstr "Søppelpost" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Bekreftet" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Flere tommeler ned enn opp" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Tittel-nøkkelord" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Kommaseparert liste" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Serverlastbalansering" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Forhindre lastbalansering" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Tillat lastbalansering" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Tillat lastbalansering med optimalisering for IPv6" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "Nyttig hvis en newsserver har mer enn en IPv4/IPv6-adresse" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Legg til server" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Serverbeskrivelse" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Port" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Brukernavn" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Passord" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Tidsavbrudd" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Tidsrom for liggefrist" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Deaktivert" #: sabnzbd/skintext.py msgid "Minimal" msgstr "" #: sabnzbd/skintext.py msgid "Strict" msgstr "" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 er høyeste prioritet, 100 er laveste prioritet" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Valgfritt" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Aktivere" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Ta bort server" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Testserver" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Nullstill Tellere" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Tester serverinstillinger..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Båndbredde" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Send gruppe" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Send gruppekommando før du ber om artikler." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Bruk denne serveren kun for disse kategoriene" #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Persolige notater" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Legg til nedlastingsplan" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Aktuelle nedlastingsplaner" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "Avkrysningsboksen ved kildenavnet må aktiveres for at kilden automatiskt " "skal kontrolleres for nye objekt.
Når en kilde legges til, legges det " "kun til nye objekt(ikke objekt som allerede finnes). Alle objekter i kilden " "vises når du klikker på \"Tving nedlastning\"." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Les kilde" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Tving nedlasting" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Filter" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Akseptere" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Avvise" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Krever" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "KreverKat" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Minst" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Høyst" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "Fra SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Like" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Ingen treff" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Nedlastet" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Les alle kilder nå" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "E-Post varsling når nedlasting er ferdig" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Aldri" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Alltid" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Bara ved feil" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Full harddisk varsling" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "Send e-post når harddisken er full og SABnzbd har pauset." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Send RSS varsler" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "Send e-post nå en RSS feed legger til en nedlasting til køen." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "SMTP-tjener" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Still inn din ISP's server for utgående e-post." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "E-post mottaker" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "E-post adresse til mottaker." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "E-post avsender" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Hvem skal vi sende e-posten fra?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "VALGFRITT Brukernavn" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Brukernavn for e-post som krever autentisering." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "VALGFRITT Passord" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Passord for e-post som krever autentisering." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Aktiver Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Send varsler til Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Brukes kun for fjerntliggende Growl tjener (vert:port)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Passord for tjener" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Valgfritt passord for Growl tjener" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "Aktiver NotifyOSD" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Send varsler til NotifyOSD" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Varselsenter" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Send varsler til Varselsenter" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Windows-varslinger" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Aktiver Windows-varslinger" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Aktiver Prowl-varslinger" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Krever en Prowl-konto" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "API-nøkkel for Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Personlig API-nøkkel for Prowl (påkrevd)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Aktiver Pushover-varslinger" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Krever en Pushover-konto" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Program-token" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Program-token (påkrevd)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Brukernøkkel" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Brukernøkkel (påkrevd)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Enhet(er)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Enhet(er) som meldingen skal sendes til" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Aktiver Pushbullet-varslinger" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Krever en Pushbullet-konto" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Personlig API-nøkkel" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Din personlige Pushbullet API-nøkkel (påkrevd)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Enhet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Enheten meldingen skal sendes til" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Ved å avslutte filstien med en asterisk * vil arbeidsmapper ikke bli " "opprettet" #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Relative mapper er basert på" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Mappe/Søkesti" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Seriesortering" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Aktiverer TV sortering" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Hjelp til Sorteringsstreng" #: sabnzbd/skintext.py msgid "Clear" msgstr "Rens" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "" #: sabnzbd/skintext.py msgid "Presets" msgstr "For innstillinger" #: sabnzbd/skintext.py msgid "Example" msgstr "Eksempel" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Aktiver filmsortering" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "La nedlastningen i ekstramappe være" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Påvirkede kategorier" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Betyr" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Mønster" #: sabnzbd/skintext.py msgid "Result" msgstr "Resultat" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Sesongmappe" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Sesongmappe" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Episodemappe" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Episodemappe" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Tittel" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Film Navn" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Film.Navn" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Film_Navn" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Show Navn" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Show.Navn" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Show_Navn" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Sesongnummer" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Episodenummer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Episodenavn" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Episode.Navn" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Episode_Navn" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Filendelse" #: sabnzbd/skintext.py msgid "Extension" msgstr "endelse" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Delnummer" #: sabnzbd/skintext.py msgid "Decade" msgstr "Titall" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Originalfilnavn" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Små bokstaver" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEKST" #: sabnzbd/skintext.py msgid "text" msgstr "tekst" #: sabnzbd/skintext.py msgid "file" msgstr "fil" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Sorteringsstreng" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Multi-del etikett" #: sabnzbd/skintext.py msgid "In folders" msgstr "I mappe" #: sabnzbd/skintext.py msgid "No folders" msgstr "Ingen mappe" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Dato sortering" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Aktiver datosortering" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Vis Navn på mappe" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "År-Måneds mapper" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Daglige mapper" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "justert for store og små bokstaver" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Prosesser resultat" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Sjeldent brukte valg. for å finne forklaring og betydning, klikk på " "hjelpknappen for å gå til Wiki siden.
Ikke endre på disse uten å sjekke " "Wiki først, siden noen av dem har alvorlige bieffekter.
Standardverdiene " "står i parantes." #: sabnzbd/skintext.py msgid "Values" msgstr "Verdier" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Endre NZB detaljer" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Fjern" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Topp" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Opp" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Ned" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Bunn" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Alle" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Invertere" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Filnavn" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Emvne" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Utvalg" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Pause 5 minutter" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Pause 15 minutter" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Pause 30 minutter" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Pause 1 time" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Pause 3 timer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Pause 6 timer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "gjenstår" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Ledig plass" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Midlertidig Mappe" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Multioperasjoner" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Hold shift-tasten for å velge et område" #: sabnzbd/skintext.py msgid "Check all" msgstr "Merk alle" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Start SABnzbd på nytt" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Status og grensesnittalternativer" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Eller dra og slipp filer i vinduet!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Mistet tilkobling til SABnzbd.." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "" "Hvis SABnzbd skulle starte på nytt vil denne skjermen forsvinne automatisk!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "ADVARSEL:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Hent" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Oppdateringsfrekvens" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Bruk globale grensesnittinnstillinger" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Kø-grense" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Historikk-grense" #: sabnzbd/skintext.py msgid "Date format" msgstr "Datoformat" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Ekstra kø-kolonne" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "side" #: sabnzbd/skintext.py msgid "Loading" msgstr "Laster" #: sabnzbd/skintext.py msgid "articles" msgstr "artikler" #: sabnzbd/skintext.py msgid "Rename" msgstr "Endre navn" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Reparer Kø" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Vis aktive tilkoblinger" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Etterlatte jobber" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Send tilbake til kø" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Ta bort alle" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Prøv alle på nytt" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Hent NZB fra URL" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "Last opp NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Valgfritt spesifiser filnavn" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Formater: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Send" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Åpne informasjons-URL" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Sendt. Takk!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Ingenting er valgt!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Fjern alle valgte filer" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Skjul/vis fullførte filer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Se skriptlogg" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Oppdatering tilgjengelig" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Tilpasse" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Hastighet" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Bekreft Sletting av Kø" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Bekreft Sletting av Historie" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Hvor lenge ønsker du å pause? (skriv på engelsk!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Beklager, vi kunne ikke finne ut av det. Prøv igjen." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Pause i..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Oppdatere" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Sorter etter alder Eldst→Ny" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Sorter etter alder Ny→Eldst" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Sorter etter navn A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Sorter etter navn Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Sorter etter størrelse Minst→Størst" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Sorter etter størrelse Størst→Minst" #: sabnzbd/skintext.py msgid "Uploading" msgstr "" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "" #: sabnzbd/skintext.py msgid "Removing job" msgstr "" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Forrige" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Neste" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Vil du virkelig slette historikken?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Du må aktivere Javaskript for at Plush skal fungere!" #: sabnzbd/skintext.py msgid "Options" msgstr "Alternativer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Pause i hvor mange minutter?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Toppmeny" #: sabnzbd/skintext.py msgid "On Finish" msgstr "Ved avslutning" #: sabnzbd/skintext.py msgid "Sort" msgstr "Sortere" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Sorter på Alder (Eldst%rarr;Yngst)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Sorter på Alder (Yngst%rarr;Eldst)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Sorter på Navn (A%rarr;Å)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Sorter på Navn (Å%rarr;A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Sorter på Størrelse (Minst→Størst)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Sorter på Størrelse (Størst→Minst)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Vil du virkelig slette køen?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Prøv alle mislykkede jobber i historikken på nytt?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Slett og rydd" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Maks. hastighet" #: sabnzbd/skintext.py msgid "Range" msgstr "Intervall" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Bruk på Valgte" #: sabnzbd/skintext.py msgid "Everything" msgstr "Alt" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Oppdateringsfrekvens" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Kontainer bredde" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "Dette vil hindre oppfrisking av innhold når muspekeren er over køen" #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Blokker oppfrisking når musen svever over" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Last Opp" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Last Opp: .nzb .rar .zip .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Jobb" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Ikke nok diskplass for å fullføre nedlastingen." #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Ledig (midlertidig)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "INAKTIV" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Nedlastinger" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Slett Ferdige" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Ta bort alle feilmeldinger fra historikken?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Slett Mislykkede" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Prøv alle mislykkede jobber på nytt?" #: sabnzbd/skintext.py msgid "Links" msgstr "Lenker" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Viser %s til %s av %s resultat" #: sabnzbd/skintext.py msgid "No results" msgstr "Ingen resultater" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Viser et resultat" #: sabnzbd/skintext.py msgid "First" msgstr "Første" #: sabnzbd/skintext.py msgid "Last" msgstr "Siste" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "Sendte E-post!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Varsel sendt!" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Lagrer.." #: sabnzbd/skintext.py msgid "Saved" msgstr "Lagret" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Vis/Skjul Legg til NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "Visning 1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "Visning 2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Er du sikker på at du vil omstarte SABnzbd?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Skjul redigeringsalternativer" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Vis redigeringsalternativer" #: sabnzbd/skintext.py msgid "Edit" msgstr "Endre" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Gjenstår" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "SABnzbd Hurtigstart Guide" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "SABnzbd Versjon" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Forrige" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Serverinstillinger" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Skriv inn opplysningene om din primære usenet leverandør." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Antallet tilkoblinger som er tillatt av din leverandør" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "F.eks 8 eller 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Velges kun om din leverandør tillater SSL-tilkoblinger." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Klikk her for å teste serverinstillingene." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Eks." #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "Installasjonen er nå ferdig!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd kommer nå å kjøres i bakgrunnen." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "" "SABnzbd kommer ikke til å avsluttes om du lukker vinduet eller fanen i " "webleseren." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Det er anbefalt at du lagrer denne siden som et bokmerke for å treffe " "SABnzbd når det kjøres i bakgrunnen." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Øvrig hjelp kan du finne på vår" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Gå til SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Avslutt SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Start Veiviser" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd kommer HELT UTEN GARANTI.\n" "Dette er fri programvare, og du kan redistribuere det under visse vilkår.\n" "Det er lisensier under GNU GENERAL PUBLIC LICENSE Versjon 2 eller senere " "versjoner.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "For å laste ned fra usenet trenger du tilgang til en leverandør. Din " "internettleverandør kan gi deg tilgang, men en \"proff\" leverandør " "anbefales." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "Har du ikke noen usenet leverandør? Vi anbefaler å prøve %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Kunne ikke hente TV info (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Kunne ikke endre navn fra: %s til %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Kunne ikke endre navn på lik fil: %s til %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Kunne ikke finne servernavn" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Uautorisert tilgang" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "URLGRABBER KRASJET" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Feil, Ubrukelig akrivfil" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "URL henting mislyktes; %s" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "Mappen \"%s\" finnes ikke" #~ msgid "SQL Commit Failed, see log" #~ msgstr "SQL Innsetting mislyktes, se logg" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "Kunne ikke finne noen UNRAR program, utpakking er ikke mulig
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "Kunne ikke finne noen PAR2 program, reparasjon er ikke mulig
" #~ msgid "Initiating restart...
" #~ msgstr "Forbereder omstart...
" #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "\"%s\" jobber er igjen i køen" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "Nedlasting markert med '*' kommer ikke å bli lastet ned automatisk." #~ msgid "Not matched" #~ msgstr "Ulike" #~ msgid "Downloaded so far" #~ msgstr "Nedlastet en så lenge" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Kan ikke koble til registret HKEY_CURRENT_USER." #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Kan ikke åpne registernøkkel \"%s\"." #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Kunne ikke lese registernøkkel for spesialmapper" #~ msgid "You have no permisson to use port %s" #~ msgstr "Du har ikke tilgang for å bruke port %s" #~ msgid "Try again" #~ msgstr "Forsøk igjen" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "pyopenssl modul mangler, vennligst installer den for https tilgang" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Mangler forventet fil: %s => unrar feil?" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "Utpakking mislyktes, en forventet fil er ikke utpakket" #~ msgid "Main packet not found..." #~ msgstr "Hovedarkiv mangler..." #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Mislyktes med importering av OpenSSL modul. Kobler til uten SSL" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Kunne ikke fjerne nzo fra etterbehandlings køen (id)" #~ msgid "View script output" #~ msgstr "Vis skript kjøringen" #~ msgid "Queued" #~ msgstr "Satt i kø" #~ msgid "Complete Dir" #~ msgstr "Ferdig nedlastingsmappe" #~ msgid "Download speed" #~ msgstr "Nedlastingshastighet" #~ msgid "WARNINGS" #~ msgstr "ADVARSLER" #~ msgid "Add new downloads" #~ msgstr "Legg til ny nedlasting" #~ msgid " or Report ID" #~ msgstr " eller Rapport ID" #~ msgid "Sort by name" #~ msgstr "Sortere etter navn" #~ msgid "Sort by age" #~ msgstr "Sortere etter alder" #~ msgid "Sort by size" #~ msgstr "Sortere etter størrelse" #~ msgid "Hide files" #~ msgstr "Skjul filer" #~ msgid "Show files" #~ msgstr "Vis filer" #~ msgid "Remain/Total" #~ msgstr "Gjenstår/Totalt" #~ msgid "History Size" #~ msgstr "Historikk størrelse" #~ msgid "Show Weblogging" #~ msgstr "Weblogg" #~ msgid "Thread" #~ msgstr "Tråd" #~ msgid "Email Test Result" #~ msgstr "E-post testresultat" #~ msgid "General configuration" #~ msgstr "Generell konfigurasjon" #~ msgid "Secondary Web Interface" #~ msgstr "Endre utseende til Webgrensesnittet." #~ msgid "Activate an alternative skin." #~ msgstr "Aktiver ett alternativt skin." #~ msgid "Web server authentication" #~ msgstr "Webserver autentisering" #~ msgid "HTTPS Support" #~ msgstr "HTTPS Støtte" #~ msgid "Queue auto refresh interval:" #~ msgstr "Automatisk oppdateringsintervall av kø:" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "Oppdateringsintervall av kø-siden (sek, 0= ingen)." #~ msgid "Disable API-key" #~ msgstr "Slå av API-nøkkel" #~ msgid "Do not require the API key." #~ msgstr "Ikke krev API-nøkkel." #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "BRUK PÅ EGET ANSVAR!" #~ msgid "Folder configuration" #~ msgstr "Mappekonfigurasjon" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Etterbehandlings skriptmappe" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "Mappe inneholder skript for etterbehandling." #~ msgid "Switches configuration" #~ msgstr "Parameterkonfigurasjon" #~ msgid "Processing Switches" #~ msgstr "Bearbeider parameter" #~ msgid "Enable Quick Check" #~ msgstr "Aktiver Hurtigsjekk" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Ikke kjør par2 kontroll når filene er 100% korrekte." #~ msgid "Enable Unrar" #~ msgstr "Aktiver Unrar" #~ msgid "Enable built-in unrar functionality." #~ msgstr "Aktiverer den innbyggde Unrar funksjonen." #~ msgid "Enable built-in unzip functionality." #~ msgstr "Aktiverer den inbyggde Unzip funktionen." #~ msgid "Enable Filejoin" #~ msgstr "Aktiver Filsammenslåing (Filejoin)" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "Slår sammen filer med filendelsene .001, .002 etc. til en fil." #~ msgid "Enable TS Joining" #~ msgstr "Aktiver TS Sammenslåing (TS Joining)" #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "Slår sammen filer med filendelsene .001.ts, .002.ts etc. til en fil." #~ msgid "Enable Par Cleanup" #~ msgstr "Aktiver Par rensing (Par Cleanup)" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Renser bort par filer (om verifisering/reperasjon var vellykket)." #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Ved feil på yEnc CRC" #~ msgid "Default Post-Processing" #~ msgstr "Standard etterbehandling" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "Brukes når etterbehandlingen er bestemt etter kategori." #~ msgid "Default User Script" #~ msgstr "Standard brukerskript" #~ msgid "Used when no user script is defined by the category." #~ msgstr "Brukes når brukerskript er bestemt etter kategori." #~ msgid "Default Priority" #~ msgstr "Standard prioritet" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Brukes når ingen prioritet er bestemt av kategori." #~ msgid "Enable MultiCore Par2" #~ msgstr "Aktiver MultiCore Par2" #~ msgid "Other Switches" #~ msgstr "Andre parametre" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Erstatt ulovlige tegn i mappenavn." #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Erstatt ulovlige tegn i mappenavn med tilsvarende tegn(ellers fjernes de)." #~ msgid "Do not download" #~ msgstr "Last ikke ned." #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Bruk V23 om ikke din leverandør krever noe annet!" #~ msgid "Server configuration" #~ msgstr "Serverkonfigurasjon" #~ msgid "Backup server" #~ msgstr "Reserve server" #~ msgid "Click below to test." #~ msgstr "Klikk nedenfor for å teste." #~ msgid "Scheduling configuration" #~ msgstr "Nedlastingsplan konfiguration" #~ msgid "Remove" #~ msgstr "Fjern" #~ msgid "RSS Configuration" #~ msgstr "RSS-konfigurasjon" #~ msgid "Delete Feed" #~ msgstr "Fjern feed" #~ msgid "Email Options" #~ msgstr "E-Post alternativer" #~ msgid "Email Account Settings" #~ msgstr "E-post konto innstillinger" #~ msgid "User-defined categories" #~ msgstr "Brukerdefinerte kategorier" #~ msgid "Defines post-processing and storage." #~ msgstr "Definierer etterbehandling og lagring." #~ msgid "Sorting configuration" #~ msgstr "Sorteringskonfigurasjon" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Aktiverer sortering endring av episodenavn." #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Aktiverer sortering og endring av filnavn." #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Aktiver om nedlastning ikke er flyttet til egen mappe." #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Aktiverer sortering og endring av navn på datomerkede filer." #~ msgid "Are you sure you want to delete" #~ msgstr "Er du sikker på at du vil fjerne" #~ msgid "Page" #~ msgstr "Side" #~ msgid "Close" #~ msgstr "Steng" #~ msgid "Set Pause Interval" #~ msgstr "Sett pauseintervall" #~ msgid "Pause Interval" #~ msgstr "Pauseintervall" #~ msgid "Pause for 12 hours" #~ msgstr "Pause 12 timme" #~ msgid "Pause for 24 hours" #~ msgstr "Pause 24 timer" #~ msgid "Left" #~ msgstr "Venstre" #~ msgid "Hour:Min" #~ msgstr "Time:Minutt" #~ msgid "Access" #~ msgstr "Tilgang" #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "" #~ "Jeg vil at SABnzbd skal kunne brukes fra alle datamaskiner i mitt nettverk." #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Jeg vil at SABnzbd kun skal kunne brukes fra min datamaskin." #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Passordbeskytte tilgangen til SABnzbd (anbefales)" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Aktiver HTTPS protokoll for tilgang til SABnzbd." #~ msgid "Misc" #~ msgstr "Diverse" #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "Start webleseren med SABnzbd's side når programmet startes." #~ msgid "This field is required." #~ msgstr "Detta feltet kreves." #~ msgid "Please enter a whole number." #~ msgstr "Bruk et heltall." #~ msgid "Step One" #~ msgstr "Steg en" #~ msgid "Step Two" #~ msgstr "Steg to" #~ msgid "Step Three" #~ msgstr "Steg tre" #~ msgid "Step Four" #~ msgstr "Steg fire" #~ msgid "Step Five" #~ msgstr "Steg fem" #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Ugyldige par2-filer, kan ikke kontrollere eller reparere" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Utpakking feilet, fil(er) mangler:" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd har problemer med visse programvare-baserte brannmurer.
\n" #~ " %s
\n" #~ " Uheldigvis kan ikke dette problemet løses akkurat nå.
\n" #~ " Forhør deg med leverandøren av brannmuren din for støtte.
\n" #~ "
\n" #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Du bruker mest sannsynlig ZoneAlarm under Vista." #~ msgid "OK" #~ msgstr "OK" #~ msgid "Get NZB" #~ msgstr "Hent NZB" #~ msgid "KB/s" #~ msgstr "KB/s" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "ADVARSEL: Jobb \"%s\" satt på pause pga. kryptert RAR-fil" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "CRC-feil i %s (%s -> %s)" #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Din versjon av UNRAR er ikke anbefalt, hent en ny versjon fra " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgid "Error: No secondary interface defined." #~ msgstr "Feil: Sekundært grensesnitt er ikke definert." #~ msgid " " #~ msgstr " " #~ msgid "Delete all failed items from History?" #~ msgstr "Vil du slette alle feilete nedlastinger fra historien?" #~ msgid "Purge Failed History" #~ msgstr "Slett feil-historie" #~ msgid "QR Code" #~ msgstr "QR-kode" #~ msgid "Generic Sorting" #~ msgstr "Generell sortering" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd trenger en ledig TCP/IP-port for sin interne webserver.
\n" #~ " Port %s på %s ble forsøkt brukt, men kontoen brukt av SABnzbd har ikke " #~ "tilgang til å bruke den.
\n" #~ " På OSX og Linux-systemer må standardbrukere benytte seg av port 1023 " #~ "eller høyere.
\n" #~ "
\n" #~ " Start SABnzbd på nytt med et annet portnummer." #~ msgid "New Feed URL" #~ msgstr "Ny RSS-kilde adresse" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "ADVARSEL: Avbrutt jobb \"%s\" grunnet kryptert RAR fil" #~ msgid "Feeds" #~ msgstr "Kilder" #~ msgid "Add Feed" #~ msgstr "Legg til kilde" #~ msgid "Skip" #~ msgstr "Hopp over" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "Hvis artikkelen har CRC feil, prøv å hent den fra en annen server." #~ msgid "Check result of unpacking" #~ msgstr "Sjekk utpakkingsresultat" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "Sjekk utpakkingsresultat (må være av for noen filsystemer)." #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Bruk 12 timers klokke (AM/PM)" #~ msgid "SSL type" #~ msgstr "SSL type" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Vis tider i AM/PM (påvirker ikke kjøreplanen)" #~ msgid "Only for optional servers" #~ msgstr "Kun for valgfrie servere" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Bruke maksimum forsøk kun på valgfrie servere" #~ msgid "Server definition" #~ msgstr "Server definisjon" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "" #~ "Aktiver hvilke meldingsklasser som skal rapporteres (ingen, en eller flere)" #~ msgid "Notification classes" #~ msgstr "Varselklasser" #~ msgid "Open Source URL" #~ msgstr "Åpen kildekode URL" #~ msgid "Original Foldername" #~ msgstr "Originalt mappenavn" #~ msgid "Groups / Indexer tags" #~ msgstr "Grupper / Indeks etiketter" #~ msgid "Plush Options" #~ msgstr "Plush Valg" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Last opp: .nzb .rar .zip .gz" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Les kildestrøm vil hente gjeldende kildestrømsinnhold. " #~ "Tving Nedlasting Vil laste ned alle samsvarende NZB'er nå." #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "Etter at SABnzbd har startet på nytt får du tilgang på følgende adresse: %s" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "F.eks 199 eller 563 for SSL" #~ msgid "Filters" #~ msgstr "Filtere" #~ msgid "Settings" #~ msgstr "Innstillinger" #~ msgid "Storage" #~ msgstr "Lagring" #~ msgid "OZnzb" #~ msgstr "OZnzb" #~ msgid "Site API Key" #~ msgstr "Sidens API Key" #~ msgid "Automatic Feedback" #~ msgstr "Automatisk Tilbakemelding" #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Forbedret funksjonalitet inkludert karakterer og ekstra statusinformasjon er " #~ "tilgjengelig når du er koblet til OZnzb-indekserer." #~ msgid "Enable OZnzb Integration" #~ msgstr "Aktiver OZnzb-Integrasjon" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Denne nøkkelen gir identitet til indekserer. Referer til " #~ "https://www.oznzb.com/profile." #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "" #~ "Send automatisk beregnet valideringsresultater for nedlastinger til " #~ "indekserer." #~ msgid "folder" #~ msgstr "mappe" SABnzbd-2.3.2/po/main/nl.po0000644000000000000000000046071013217005051013444 0ustar 00000000000000# Dutch translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2017-12-08 10:47+0000\n" "Last-Translator: Safihre \n" "Language-Team: Dutch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-09 05:32+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Webinterface kan niet gestart worden" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "Websjabloon %s niet te vinden; het standaardsjabloon wordt gebruikt." #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" "SABYenc uitgeschakeld, geen bruikbare versie gevonden! (V%s gevonden, V%s " "verwacht)" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" "SABYenc module... NIET gevonden! Verwacht V%s - https://sabnzbd.org/sabyenc" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "_yenc-module niet gevonden." #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "par2-programma niet gevonden." #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "Verificatie en reparatie zal niet mogelijk zijn." #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "MultiPar niet gevonden!" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" "De UNRAR-versie is %s, we adviseren versie %s of hoger te gebruiken.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "Het zal niet mogelijk zijn downloads uit te pakken." #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "unrar-programma niet gevonden." #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "unzip-programma niet gevonden." #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "7za-programma niet gevonden." #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Let op: als je 0.0.0.0 als hostnaam gebruikt, heb je voor externe toegang " "een IPv6-adres nodig" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "HTTP- en HTTPS-poort kunnen niet hetzelfde zijn" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" "SABnzbd is gestart met de codering %s, dit zou UTF-8 moeten zijn. Je kunt, " "bij het downloaden, problemen krijgen met Unicode namen van bestanden en " "mappen." #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "HTTPS is uitgeschakeld vanwege ontbrekende CERT- en KEY-bestanden" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Webinterface kon niet gestart worden: " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "Geen verbinding mogelijk met de SABHelper-service" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s is gestart" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Waarschuwing" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Fout" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "SABnzbd is afgesloten" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Geen hostnaam opgegeven." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "" "Er zijn geen verbindingen opgegeven. Er is minimaal één verbinding nodig." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Wachtwoord gemaskeerd met ******, voer opnieuw in" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Ongeldige servergegevens" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "" "Tijdslimiet overschreden. Probeer met SSL aan of gebruik een andere poort." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Tijdslimiet overschreden" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" "Onbekend SSL protocol: probeer het zonder SSL of probeer een andere poort." #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Ongeldige servernaam" #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "De server stopte tijdens de login" #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Server heeft een gebruikersnaam en een wachtwoord nodig." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Succesvol verbonden!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Inloggen mislukt, controleer gebruikersnaam en wachtwoord." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "Te veel verbindingen, onderbreek het downloaden of probeer later nog eens." #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Kan verbindingsresultaat niet bepalen (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Signaal %s ontvangen, opslaan en afsluiten..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Onherstelbare fout bij opslaan status" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Probeer NZB op te halen van %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Opslaan van %s lukt niet" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Kan geen tijdelijk bestand maken voor %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Poging de status van niet-bestaande server %s in te stellen" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Probleem met tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Inlezen van %s mislukt" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Inlezen %s mislukt (foutmelding %s)" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Test melding" #: sabnzbd/api.py msgid " Resolving address" msgstr " Adres opzoeken" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Geen" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Standaard" #: sabnzbd/api.py msgid "unknown" msgstr "onbekend" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Het compileren van 'regex' voor de zoekterm lukt niet: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "Te weinig schijfruimte, pauze geforceerd" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Schijf is vol; gedwongen pauze" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Schrijffout bij opslaan van bestand %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Onherstelbare fout in de Assembler" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" "WAARSCHUWING: Download \"%s\" is gepauzeerd vanwege een versleuteld RAR " "bestand (indien aanwezig, zijn alle wachtwoorden geprobeerd)" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" "WAARSCHUWING: Download \"%s\" is afgebroken vanwege een versleuteld RAR " "bestand (indien aanwezig, zijn alle wachtwoorden" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Afgebroken, versleuteling ontdekt" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "WAARSCHUWING: Ongewenste extensie ontdekt in \"%s\". Het ongewenste bestand " "is \"%s\" " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "De ongewenste extensie zit in RAR-bestand %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Afgebroken, ongewenste extensie ontdekt" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "WAARSCHUWING: Download '%s' gepauzeerd vanwege rating (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "WAARSCHUWING: Download '%s' afgebroken vanwege rating (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Afgebroken, ratingfilter komt overeen (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s ontbreekt" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" "Download \"%s\" is waarschijnlijk versleuteld omdat en een RAR met dezelfde " "naam in de hoofd RAR zit." #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" "Download \"%s\" is waarschijnlijk versleuteld, omdat \"password\" in de naam " "\"%s\" voor komt." #: sabnzbd/assembler.py msgid "video" msgstr "video" #: sabnzbd/assembler.py msgid "audio" msgstr "audio" #: sabnzbd/assembler.py msgid "spam" msgstr "spam" #: sabnzbd/assembler.py msgid "passworded" msgstr "van wachtwoord voorzien" #: sabnzbd/assembler.py msgid "downvoted" msgstr "negatief beoordeeld" #: sabnzbd/assembler.py msgid "keywords" msgstr "trefwoorden" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Quotum verbruikt, download is gestopt" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s is geen geldig e-mailadres" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Serveradres verplicht" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Niet mogelijk %s map %s aan te maken" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Schrijven naar het INI-bestand %s lukt niet" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Backupbestand maken voor %s niet mogelijk" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Foutief gecodeerd wachtwoord %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s is geen correct octaal getal" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "UNC-pad '%s' hier niet toegestaan." #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Fout: het opgegeven pad mag niet langer zijn dan %s." #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Fout: Wachtrij is niet leeg, andere map kiezen niet mogelijk." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "" "Naar de geschiedenis-database schrijven niet mogelijk, controleer de " "toegangsrechten." #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "" "Beschadigde geschiedenis-database, is vervangen door een lege database" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "SQL-commando mislukt, zie logbestand" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Het lukt niet om de database te sluiten, zie log" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Ongeldig loggen van fase in geschiedenis voor %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Decoderen van %s mislukt" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "Decoder fout: onvoldoende geheugen" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Slecht opgemaakt yEnc-artikel in %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Onbekende fout tijdens het decoderen van %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "UUencode gevonden, SABnzbd verwerkt alleen yEnc-codering [%s]" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => ontbreekt op alle servers, overslaan" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "Direct Uitpakken" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Voltooid" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "%s bestanden/mappen uitgepakt in %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "Direct Uitpakken is automatisch ingeschakeld." #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" "Het uitpakken van downloads wordt al gestart tijdens het downloaden. Dit " "verkort de tijd die nodig is voor het nabewerken. Dit werkt alleen als de " "download niet beschadigd is." #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "%s kan niet gelezen worden" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Fout bij toevoegen van %s, wordt weer verwijderd" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Fout bij verwijderen van %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Bewaakte map %s kan niet gelezen worden" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Hervatten" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Gepauzeerd" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Je moet eerst een maximumbandbreedte instellen voordat je een limiet kunt " "instellen" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Server %s wordt gedurende %s minuten genegeerd" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Initialisatie van %s@%s mislukt, vanwege: %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "Te veel verbindingen met server %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Mogelijk delen van account" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Aanmelden bij server %s mislukt" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Verbinding maken met server %s [%s] niet mogelijk" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "Verbinding %s@%s mislukt, bericht=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Server %s heeft gebruikersnaam/wachtwoord nodig" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Vedachte fout in downloader" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Afsluiten" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Verbinding met e-mailserver mislukt" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "TLS-verbinding mislukt" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "De server reageerde niet op de 'helo'-begroeting" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Aanmelden bij e-mailserver mislukt" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Geen geschikte authenticatiemethode gevonden" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "Onbekende authenticatiefout bij de e-mailserver" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Verzenden van e-mail is mislukt" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Beëindigen e-mailverbinding mislukt" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "E-mail verzonden" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Versturen kan niet, vereiste gegevens ontbreken" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Geen e-mailsjablonen te vinden in %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Geen geadresseerden opgegeven, e-mail niet verstuurd" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Foutieve codering van e-mailsjabloon %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Geen e-mailsjablonen gevonden" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd meldt een volle harde schijf\n" "\n" "Hallo,\n" "\n" "SABnzbd is gestopt met downloaden omdat de harde schrijf bijna vol is.\n" "Maak ruimte vrij en laat SABnzbd weer doorgaan.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "Let op: LOCALHOST is niet eenduidig, gebruik een numeriek IP-adres." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Serveradres \"%s:%s\" is niet geldig." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "Gebruiker heeft ingelogd" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "Gebruiker ingelogd" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Sessiesleutel ontbreekt" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Fout: Sessie sleutel nodig" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Fout: Sessiesleutel niet geldig" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "API-sleutel ontbreekt; vul de API-sleutel van 'Configuratie' => 'Algemeen' " "in bij het externe programma:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "API-sleutel incorrect; vul de API-sleutel van 'Configuratie' => 'Algemeen' " "in bij het externe programma:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Autenticatie ontbreekt; vul gebruikersnaam en wachtwoord van 'Configuratie' " "=> 'Algemeen' in bij het externe programma:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Probeer onze nieuwe skin Glitter. Compleet nieuw design, geoptimaliseerd " "voor desktops en mobiele apparaten. Ga naar Configuratie => Algemeen om de " "huidige skin te vervangen." #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "Mislukte login progin bij %s" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
SABnzbd is nu afgesloten.
Wacht ongeveer 5 seconden en klik " "dan op onderstaande knop.

Verversen
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Feed" #: sabnzbd/interface.py msgid "Daily" msgstr "dagelijks" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "maandag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Dinsdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Woensdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Donderdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Vrijdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Zaterdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Zondag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "uit" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Onbekende server." #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Incorrecte parameter" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" "Een Categorie specifieke map mag niet een map in de Tijdelijke download map " "zijn." #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Terug" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "FOUT:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Foute waarde voor %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "d" #: sabnzbd/misc.py msgid "h" msgstr "h" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Niet mogelijk directory %s aan te maken" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "%s directory: fout %s bij toegang" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Aanmaken (%s) mislukt" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Verplaatsen van %s naar %s mislukt" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Fout bij aanmaken SSL-sleutel en -certificaat" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" "Je wachtwoordenbestand bevat meer dan 30 wachtwoorden, het testen van al " "deze wachtwoorden kost heel veel tijd. Zorg ervoor dat je alleen maar " "nuttige wachtwoorden in dit bestand zet." #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Toegangsrechten van %s niet aan te passen" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Script uitvoeren" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Nabewerking is afgebroken (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Script" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Teveel niveaus om uit te pakken [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Samenvoegen" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Onvolledige reeks van samenvoegbare bestanden" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Samenvoegen van bestanden %s is mislukt" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Fout \"%s\" bij samenvoegen van bestanden" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Fout %s bij 'file_join' op %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] %s bestanden samengevoegd" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Uitpakken mislukt, %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Fout \"%s\" bij het uitpakken van RAR-bestanden" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Fout \"%s\" bij uitvoeren van 'rar_unpack' op %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Verwijderen van %s mislukt." #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Unrar proberen met wachtwoord \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Uitpakken mislukt, archief vereist wachtwoord" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Uitpakken" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Uitpakken" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Uitpakken mislukt, kan %s niet vinden" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "FOUT: \"%s\" niet te vinden" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Uitpakken mislukt, CRC-fout" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "FOUT: onjuiste CRC in \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "Uitplakken mislukt, bestand te groot voor het bestandssysteem (FAT?)" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "FOUT: bestand te groot voor het bestandssysteem (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "Uitpakken mislukt, schrijffout of schijf vol?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "FOUT: schrijffout (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Uitpakken mislukt, bestandspad is te lang" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "FOUT: bestandspad is te lang (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Uitpakken mislukt, zie log" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "FOUT: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Onbruikbaar RAR-bestand" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "Beschadigd RAR-bestand" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s bestanden in %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Fout '%s' bij uitvoeren van unzip() op %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Uitpakpoging met 7zip en wachtwoord '%s'" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "De 7Zip-set '%s' is incompleet, uitpakken is niet mogelijk" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Uitpakken %s niet mogelijk" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Snelle controle" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Reparatie" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Snelle Controle OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Reparatie starten" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "Par-verificatie van %s misgelukt, maar QuickCheck wel gelukt." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Reparatie mislukt, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Fout %s bij uitvoeren van par2-reparatie op set %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Fout '%s' bij reparatie van set %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] PAR2-opties incorrect, controleer Configuratie=>Instellingen schakelaars" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] %s geverifieerd, alle bestanden zijn goed" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Geverifieerd in %s, reparatie is nodig" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" "Ongeldige par2 bestanden of ongeldige Par2 parameters, kan niet verifiëren " "en repareren." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "%s herstelblokken downloaden..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Ophalen" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "Reparatie mislukt, te weinig herstelblokken (%s tekort)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Repareren" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Gerepareerd in %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "Reparatie controleren" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Schijf is vol" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Verifiëren" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "Controleren van extra bestanden" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Controleren" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "Python-script '%s' heeft geen uitvoerpermissie (+x)" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "De server staat geen SSL toe op deze poort" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" "Servernaam komt niet overeen met de servernamen in het certificaat. Dit is " "een server-probleem." #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" "Certificaat niet geldig. Dit is hoogstwaarschijnlijk een server-probleem." #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "Server %s gebruikt een niet betrouwbaar certificaat [%s]" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Opstarten/Afsluiten" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "Download toegevoegd" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Nabewerken gestart" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Download voltooid" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Download mislukt" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Wachtrij voltooid" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Andere berichten" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Niet beschikbaar" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Verzenden van Prowl-bericht mislukt" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Slecht antwoord van Pushover (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Pushover-bericht sturen mislukt" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Slecht antwoord van Pushbullet (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Pushbullet-bericht sturen mislukt" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "Script gaf code %s en resultaat '%s'" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "Meldingsscript '%s' bestaat niet" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "Versturen Windows-melding mislukt" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "Oude wachtrij gevonden, gebruik Status->Reparatie om te converteren" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Onbruikbaar wachtrij bestand gevonden, kan niet verder" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Fout bij inladen van %s, corrupt bestand gevonden" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "Download kon niet herstart worden na de voor-controle (%s)." #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "Download aan wachtrij toegevoegd" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Onbekende codering" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Bestand %s is leeg, overslaan" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Importeren van %s bestanden van %s mislukt" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Onvolledig NZB-bestand %s" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Foutief NZB-bestand %s, overslaan (reden=%s, regel=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "NZB-bestand %s is leeg" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "Wachtrij filter script heeft de download afgekeurd" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Dubbele download \"%s\" overgeslagen" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "Download '%s' geweigerd omdat het een dubbele is" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "Dubbele download" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Dubbele download \"%s\" gepauzeerd" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Afgebroken, kan niet voltooid worden" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "DUBBEL" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "VERSLEUTELD" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "TE GROOT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "ONVOLLEDIG" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "ONGEWENST" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "GEFILTERD" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "WACHT %s sec" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "VERSPREIDINGSWACHTTIJD %s min" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Gedownload in %s met een gemiddelde snelheid van %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Leeftijd" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s artikelen zijn misvormd" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s artikelen ontbreken" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s artikelen hadden afwijkende duplicaten" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s artikelen zijn verwijderd" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Fout bij importeren van %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Meldingen" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Rust" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Instellingen" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Wachtrij" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Wis wachtrij" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Geschiedenis" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Wis de volledige geschiedenis" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Beperk snelheid" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Pauze" #: sabnzbd/osxmenu.py msgid "min." msgstr "min." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Doorgaan" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Bewaakte map uitlezen" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Lees alle RSS-feeds uit" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Map voltooid" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Tijdelijke download map" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Probleemoplosser" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Herstart" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Herstarten zonder login" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Afsluiten" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Wachtrij Eerste 10 Items" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Leeg" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Geschiedenis Laaste 10 Items" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Nieuwe versie beschikbaar" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Ga naar Wizard" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Afsluiten..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Probleem met" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd heeft een vrije TCP/IP poort nodig voor de interne " "webserver.
\n" "Poort %s op %s is geprobeerd, maar is niet beschikbaar.
\n" "Een ander programma gebruikt de poort al of SABnzbd is al actief.
\n" "
\n" "Start SABnzbd met een ander poort nummer." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "Als je dit bericht weer krijgt, probeer dan een ander nummer.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd heeft een geldig host adres voor de interne webserver.
\n" "Je hebt een onbruikbaar adres opgegeven.
\n" "Veilige waarden zijn localhost en 0.0.0.0
\n" "
\n" "Start SABnzbd met een geldig host adres." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd heeft opgeslagen data van een andere SABnzbd versie " "gevonden
\n" " maar kan de data van deze andere versie niet opnieuw gebruiken.

\n" " Rond zo nodig eerst je werk met de andere versie af.

\n" " Herstart daarna deze versie met de optie \"--clean\".
\n" " Dit zal de huidige downloads en geschiedenis wissen!
\n" " SABnzbd las het bestand \"%s\"." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd kan de web-interface bestanden niet vinden in %s.
\n" "Installeer het programma opnieuw.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd heeft een fatale fout ontdekt:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd heeft ontdekt dat het bestand sqlite3.dll " "ontbreekt.

\n" "Sommige slecht ontworpen virusscanners verwijderen dit bestand.
\n" "Controleer je virus scaner, probeer SABnzbd opnieuw te installeren en klaag " "bij je leverancier.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Gebruik Windowstoets-R en type deze regel in (voorbeeld):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Open een \"Terminal\" venster en type deze regel in (voorbeeld):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Programma is niet opgestart!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" "Kan niet binden aan poort %s van %s. Andere software gebruikt deze poort of " "SABnzbd is al actief." #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Fatale fout" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "Kan de web-browser niet starten, geen gevonden" #: sabnzbd/panic.py msgid "Access denied" msgstr "Toegang geweigerd" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Fout %s: Je moet een geldige gebruikersnaam en wachtwoord invullen." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" "De map voor voltooide downloads %s staat op een FAT systeem, de maximale " "file omvang is dan maar 4G" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" "De module subprocessww ontbreekt. Je kunt problemen krijgen met Unicode " "namen van bestanden en mappen." #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "" "Download mislukt waarschijnlijk, slechts %s van de benodigde %s beschikbaar" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Download mislukt - Niet meer op je server(s)" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Geen nabewerking vanwege mislukte verificatie" #: sabnzbd/postproc.py msgid "Moving" msgstr "Verplaatsen" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "%s naar de wachtrij gestuurd" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Fout bij hernoemen van \"%s\" tot \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Verplaatsen van bestanden mislukt" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Gebruiker script %s loopt" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "%s is klaar" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Exit code van het script is %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Meer" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Nabewerking van %s mislukt (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "zie logbestand" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Download mislukt" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Opschonen van %s mislukt" #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Fout bij verwijderen van werkmap %s" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Download voltooid" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Kan bestemmingsmap %s niet maken" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Nabewerking" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Geen par2 groepen" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Probeer SFV-verificatie" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Sommige bestanden konden niet geverifieerd worden met \"%s\"" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Verificatie m.b.v. SFV-bestanden is gelukt" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "Probeer RAR-verificatie" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "[%s] RAR verificatie niet gelukt: %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "Versleuteld" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "RAR bestanden zijn succesvol geverifieerd" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "RAR bestanden zijn niet verifieerbaar" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Verwijderen van %s mislukt" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Kan systeem niet in slaapstand krijgen" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Kan het systeem niet in standby krijgen" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Fout bij het afsluiten van het systeem" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "Indexer id (%s) niet gevonden in het bestand met beoordelingen" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Server adres" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "API-sleutel" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" "Deze sleutel is voor je identificatie door de indexer. Kijk in je profiel op " "de website van de indexer." #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Foutieve RSS-feed definitie \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Kan RSS-feed \"%s\" niet lezen vanwege: \"%s\"" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Geen geldige inlog gegevens beschikbaar voor RSS-feed %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "Server fout (code is %s); kon geen %s van %s krijgen" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "Server %s gebruikt een onbetrouwbaar HTTPS-certificaat" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "RSS-feed %s is leeg" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Ongeschikte RSS-feed" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Lege RSS-feed gevonden (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Toon webinterface" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Open map met voltooide downloads" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Afsluiten" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Nog te doen" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "NZB toevoegen" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Foutieve taak %s om %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Onbekende actie: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Taak voor niet bestaande server %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Download" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Samenvoegen" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Bron" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Servers" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Mislukt" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Mislukt" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "Wacht" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Repareren..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Uitpakken..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Verplaatsen..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Script uitvoeren..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Extra herstelblokken downloaden..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Snelle Controle..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Verificatie..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Downloaden" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "Verspreidingswachttijd" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Frequentie" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Actie" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Parameters" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Taak" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "Server uit:" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "Server aan:" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Maximum snelheid" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Alles pauzeren" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Pauzeer nabewerken" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Hervat nabewerken" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Uitlezen RSS-feeds" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Verwijder mislukte downloads" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Verwijder voltooide downloads" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Pauzeer downloads met prioriteit \"Laag\"" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Pauzeer downloads met prioriteit \"Normaal\"" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Pauzeer downloads met prioriteit \"Hoog\"" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Hervat downloads met prioriteit \"Laag\"" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Hervat downloads met prioriteit \"Normaal\"" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Hervat downloads met prioriteit \"Hoog\"" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Schakel quotum beheer in" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Schakel quotum beheer uit" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "Pauzeer downloads met categorie" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "Hervat downloads met categorie" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Uit" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Zeer Laag" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Gematigd" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normaal" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Hoog" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Noodgeval" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Laag" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "MB" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "GB" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "uur" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "uren" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "min" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "min" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "sec" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "seconden" #: sabnzbd/skintext.py msgid "day" msgstr "dag" #: sabnzbd/skintext.py msgid "days" msgstr "dagen" #: sabnzbd/skintext.py msgid "week" msgstr "week" #: sabnzbd/skintext.py msgid "Month" msgstr "maand" #: sabnzbd/skintext.py msgid "Year" msgstr "jaar" #: sabnzbd/skintext.py msgid "January" msgstr "Januari" #: sabnzbd/skintext.py msgid "February" msgstr "Februari" #: sabnzbd/skintext.py msgid "March" msgstr "Maart" #: sabnzbd/skintext.py msgid "April" msgstr "April" #: sabnzbd/skintext.py msgid "May" msgstr "Mei" #: sabnzbd/skintext.py msgid "June" msgstr "Juni" #: sabnzbd/skintext.py msgid "July" msgstr "Juli" #: sabnzbd/skintext.py msgid "August" msgstr "Augustus" #: sabnzbd/skintext.py msgid "September" msgstr "September" #: sabnzbd/skintext.py msgid "October" msgstr "Oktober" #: sabnzbd/skintext.py msgid "November" msgstr "November" #: sabnzbd/skintext.py msgid "December" msgstr "December" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Dag van de maand" #: sabnzbd/skintext.py msgid "This week" msgstr "Deze Week" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Deze Maand" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "Vandaag" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Totaal" #: sabnzbd/skintext.py msgid "on" msgstr "aan" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parameters" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Python versie" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Startpagina" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "of" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Server" #: sabnzbd/skintext.py msgid "Comment" msgstr "Commentaar" #: sabnzbd/skintext.py msgid "Send" msgstr "Verzenden" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Annuleren" #: sabnzbd/skintext.py msgid "Other" msgstr "Overige" #: sabnzbd/skintext.py msgid "Report" msgstr "Overzicht" #: sabnzbd/skintext.py msgid "Video" msgstr "Video" #: sabnzbd/skintext.py msgid "Audio" msgstr "Audio" #: sabnzbd/skintext.py msgid "Not used" msgstr "Niet gebruikt" #: sabnzbd/skintext.py msgid "or less" msgstr "of minder" #: sabnzbd/skintext.py msgid "Log in" msgstr "Aanmelden" #: sabnzbd/skintext.py msgid "Log out" msgstr "Afmelden" #: sabnzbd/skintext.py msgid "Remember me" msgstr "Mij onthouden" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "De automatische Usenet downloader" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Opslaan" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Weet je het zeker?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Alle gedownloade bestanden verwijderen?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Startpagina" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Instellingen" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Status" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Hulp" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Forum" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "Problemen" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "Steun het project, doneer!" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Algemeen" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Mappen" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Opties" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Taakplanner" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Meldingen" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "E-mail" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Categorieën" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Sorteren" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Speciaal" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Zoeken" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Map voor verwerkte downloads" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "PAUZE" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "%s artikelen (%s) gebuffered" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Sysload" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Nieuwe versie %s beschikbaar op" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Weet je zeker dat je SABnzbd wilt afsluiten?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Toevoegen" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Bestand toevoegen" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Categorie" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Nabewerking" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Prioriteit" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Repareren" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Uitpakken" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Opschonen" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "U" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "O" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Forceren" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Stop" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "Na afronden wachtrij" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "PC afsluiten" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "PC standby" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "PC slapen" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "SABnzbd afsluiten" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Max. snelheid" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Pauzeer" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Volgorde" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Naam" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "Klaar om" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "Leeftijd" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Wis" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Opnieuw" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Acties" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Scripts" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Verwijder alle downloads uit de wachtrij?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Verwijder alle downloads" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Verwijderen incl. bestanden" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Probeer alle mislukte downloads opnieuw" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Verwijder download" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Verwijder download incl. bestanden" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "van" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Ontbrekende artikelen" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Quotum over" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "handmatig" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Quotum nu resetten" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Verwijder alle geslaagde items uit Geschiedenis?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Verberg details" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Toon details" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Toon mislukte" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Toon Alles" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Omvang" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Verwijder mislukte downloads" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Verwijder mislukte downloads incl. bestanden" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Verwijder voltooide downloads" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "Verwijder downloads op deze pagina" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "Eventuele extra NZB" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Pad" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Probeer alle mislukte" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Alles opnieuw proberen" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus/spam" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "Buiten retentie" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Ander probleem" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Verbreek verbindingen" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Hiermee stuur je een test e-mail." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Download log" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "E-mail testen" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Loggen" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Fouten/Waarschuwingen" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+Info" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+Debug" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Verbindingen" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Recentste meldingen" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "Wissen" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Deblokkeren" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Artikelnummer" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Bestandsverzameling" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Wanneer" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Filter" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Actief" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Dashboard" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Verbinding mislukt!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Lokaal IPv4-adres" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Openbaar IPv4-adres" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "IPv6-adres" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Nameserver / DNS opzoeken" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "CPU-model" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "Systeemprestaties (Pystone)" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Snelheid van download map" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Snelheid van verwerkte downloads map" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Schrijfsnelheid" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "Kan niet schrijven. Controleer of de map beschrijfbaar is." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Klik op de Herhaal Test knop om te meten" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Herhaal test" #: sabnzbd/skintext.py msgid "Config File" msgstr "Instellingen bestand" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Gebruikte buffer" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Deze knop zal SABnzbd herstarten.
Dit kan nuttig zijn wanneer je " "vermoedt dat het programma niet stabiel is.
Het downloaden zal vóór de " "herstart gestopt worden en daarna weer doorgaan." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" "
Als authenticatie ingeschakeld is, zal je opnieuw moeten inloggen." #: sabnzbd/skintext.py msgid "Advanced" msgstr "Geavanceerd" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Er staan verweesde downloads in de download map.
Je kunt ze verwijderen " "(inclusief bestanden) of ze terug naar de wachtrij sturen." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "De \"Repareren\" knop herstart SABnzbd met een complete
\r\n" "reconstructie van de wachtrij, met behoud van al gedownloade " "bestanden.
\r\n" "Dit beïnvloedt wel de volgorde." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Wijzigingen niet opgeslagen en zullen verloren gaan." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" "Als je IP adres veranderd of SABnzbd opnieuw wordt opgestart, zal de sessie " "verlopen." #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Unzip toestaan" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "7Zip toestaan" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "Multicore Par2" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" "Beveiligde (SSL) verbindingen van SABnzbd naar nieuws servers en naar HTTPS " "websites worden versleuteld. Maar verificatie van de server identiteit is " "niet mogelijk. Python 2.7.9 of hoger en OpenSSL 1.0.2 of hoger en actuele " "lokale CA certificaten zijn nodig." #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" "Versnel reparaties door multi-core par2 te installeren. Beschikbaar voor " "veel besturingssystemen." #: sabnzbd/skintext.py msgid "Version" msgstr "Versie" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Tijd in de lucht" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Reserve" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Lees de Wiki pagina over dit onderwerp" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "SABnzbd herstart nu..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Wijzigingen worden pas actief na herstart!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "Webserver" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "Host" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Host adres waar op SABnzbd luistert." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "Poort" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Poort waar op SABnzbd luistert." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Webinterface" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Kies een bedieningsstijl (herstart nodig)." #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "Gebruikersnaam" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Gebruikersnaam voor web login." #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "Wachtwoord" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Wachtwoord voor web login." #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" "Als de Host of Poort open is gesteld naar het internet zorgen de huidige " "instellingen ervoor dat de webinterface volledig beschikbaar is voor " "externen." #: sabnzbd/skintext.py msgid "Security" msgstr "Beveiliging" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "Activeer HTTPS" #: sabnzbd/skintext.py msgid "not installed" msgstr "niet geinstalleerd" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Webinterface beschikbaar via HTTPS" #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "HTTPS Poort" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Indien leeg, werkt de standaard poort uitsluitend met HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "HTTPS-certificaat" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Naam of pad naar het HTTPS-Certificaatbestand." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" "Maak een nieuw zelf-ondertekend certificaat en sleutel. SABnzbd moet dan " "opnieuw gestart worden." #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "HTTPS-sleutelbestand" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Naam of pad van het HTTPS-sleutelbestand." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "HTTPS chain-bestand" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Bestandsnaam of padnaam van HTTPS chain-bestand" #: sabnzbd/skintext.py msgid "Tuning" msgstr "Afstelling" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "RSS-feed uitlees interval" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Minuten tussen het uitlezen (minimaal 15). Niet actief bij gebruik van de " "Taakplanner!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Maximale snelheid internetverbinding" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Percentage van snelheid internetverbinding" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "" "Welk percentage van de maximale internet snelheid mag SABnzbd gebruiken? " "B.v. 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Artikelbuffer grootte" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Bewaar de artikelen in het werkgeheugen (verminderd schijf gebruik).
In bytes, in K,M,G notatie. Bijvoorbeeld: \"64M\" of \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Opschoon lijst" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Lijst van extensies die na downloaden verwijderd moeten worden.
Voorbeeld: nfo of nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "Geschiedenis Bewaren" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" "Automatisch verwijderen van voltooide downloads. Let er op dat Dubbele " "Download Detectie en andere externe tools Geschiedenis informatie nodig " "hebben." #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "Behoud alle downloads" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "Maximum aantal voltooide downloads" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "Behoud voltooide downloads maximaal aantal dagen" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "Behoud geen enkele download" #: sabnzbd/skintext.py msgid "Jobs" msgstr "Downloads" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Opslaan" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "Beginwaarden terugzetten" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Herstel" #: sabnzbd/skintext.py msgid "Language" msgstr "Taal" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Kies een taal." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" "Help ons om SABnzbd in jouw taal te vertalen!
Met nieuwe vertalingen of " "verbeteringen kun je hier terecht:" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "" "Met deze sleutel heeft een extern programma volledige toegang tot SABnzbd." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "NZB-sleutel" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "Met deze sleutel kan een extern programma NZB-bestanden naar SABnzbd sturen." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Maak een nieuwe sleutel" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "QR-code van de API-sleutel" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Lijst van lokale netwerk bereiken" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Alle lokale netwerk adressen die beginnen met deze reeks (vaak " "\"192.168.1.\")" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Externe toegang" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" "Je kunt toegangsrechten instellen voor systemen buiten je lokale netwerk. " "Hiervoor geef je een lijst van netwerk-bereiken in." #: sabnzbd/skintext.py msgid "No access" msgstr "Geen toegang" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Voeg NZB-bestanden toe " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (geen Configuratie)" #: sabnzbd/skintext.py msgid "Full API" msgstr "Volledige API" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Volledig webinterface" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "Alleen voor externe toegang is aanmelden nodig" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "Let op: mappen worden vanzelf aangemaakt bij \"Opslaan\"." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Gebruikersmappen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Bladeren" #: sabnzbd/skintext.py msgid "In" msgstr "In" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Tijdelijke download map" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Map om onbewerkte downloads op te slaan
Kan alleen gewijzigd worden " "als de wachtrij leeg is." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Minimale vrije ruimte voor tijdelijke download map" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "Download wordt gepauzeerd als er te weinig ruimte vrij is" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Map voor verwerkte downloads" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "(kan aangepast worden door de categorieën)." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Toegangsrechten voor verwerkte downloads" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Zet toegangsrechten voor verwerkte bestanden/mappen, alleen octale notatie!" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Bewaakte map" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" ".NZB en .ZIP-bestanden in deze map worden automatisch toegevoegd aan de " "wachtrij." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Bewaakte map verversingsinterval" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Aantal seconden tussen het lezen van de bewaakte map." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "Map voor scripts" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "Map met scripts van de gebruiker" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Map met e-mailsjablonen" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Map met e-mailsjablonen." #: sabnzbd/skintext.py msgid "Password file" msgstr "Wachtwoordenbestand" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Bestand met alle wachtwoorden die uitgeprobeerd moeten worden op " "versleutelde RAR-bestanden." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Systeemmappen" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Administratieve map" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Map waar de wachtrij en geschiedenisdatabase worden opgeslagen.
Kan " "alleen gewijzigd worden als de wachtrij leeg is." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "De bestanden worden niet verplaatst. SABnzbd moet herstart " "worden!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Map voor logging" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Map waarin de log bestanden worden opgeslagen
Vereist een " "herstart." #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr "Map voor het bewaren van NZB-bestanden" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Map waar reserve kopieën opgeslagen worden." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Basis map" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Download alle PAR2-bestanden" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" "Dit voorkomt extra reparatie pogingen, doordat alle beschikbare par2 files " "direct worden gedownload." #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Recursief uitpakken toestaan" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Uitpakken van archieven (rar, zip, 7z) binnen archieven toestaan" #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Negeer mappen binnen archieven" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Alle bestanden gaan in één map" #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Download alleen artikelen van het begin van de wachtrij" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Aanzetten zal leiden tot minder geheugen gebruik.
Uitzetten om te " "voorkomen dat langzame downloads de wachtrij blokkeren." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Verwerk alleen correct geverifieerde downloads" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "" "Voer de nabewerking alleen uit op downloads die de PAR2 controles hebben " "doorlopen." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Actie wanneer versleuteld RAR-bestand wordt gedownload" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "Als je \"Pause\" kiest, dan dien je een wachtwoord in te stellen en de " "download vrij te geven" #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Detecteer dubbele downloads" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" "Detecteer identieke downloads (op basis van downloads in je Geschiedenis of " "bestanden in je .nzb backup map)." #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Detecteer dubbele afleveringen in series" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" "Detecteer identieke afleveringen in series (gebaseerd op " "\"naam/seizoen/aflevering\" van downloads in je Geschiedenis)." #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "Sta verbeterde downloads toe" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" "Sla dubbele download detectie over als er in de naam van de download PROPER, " "REAL of REPACK bevat" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Verwerpen" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "Keur download af" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "Label download" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Afbreken" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Actie bij ontdekken van ongewenste extensie" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "" "Actie wanneer een ongewenste extensie wordt gevonden in een RAR-bestand" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Ongewenste extensies" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Lijst van alle ongewenste extensies. Voorbeeld: exe or exe, com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Voer SFV-gebaseerde controles uit" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Doe een extra verificatie m.b.v. SFV-bestanden" #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Een gebruikersscript kan een download afkeuren" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Wanneer het script een exit code anders dan 0 geeft, zal de download worden " "afgekeurd." #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "Bij mislukking: probeer alternatieve NZB" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "" "Sommige indexers hebben een alternatieve NZB wanneer een download mislukt" #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "Gebruik indexer informatie" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" "Maak tijdens het sorteren gebruik van informatie van de indexer zoals titel, " "seizoen, aflevering, enz. Anders wordt alle informatie uit de naam van de " "download gehaald." #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Gebruik tijdelijke mapnamen" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Gebruik tijdelijke mapnamen tijdens de nabewerking. Zet dit uit wanneer je " "systeem daar problemen mee heeft." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Wachtrij-filter script" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Word uitgevoerd vóór een download aan de wachtrij word toegevoegd" #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Extra PAR2 parameters" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "\"Nice\" parameters" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "\"IONice\" parameters" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Verbreek verbindingen wanneer er niets te doen is" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "" "Verbreek verbindingen wanneer de wachtrij leeg is of er gepauzeerd wordt." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Sorteer op leeftijd" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Automatisch sorteren op basis van gemiddelde leeftijd." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" "Downloads zullen gepauzeerd worden tot ze minimaal deze leeftijd hebben. " "Instellen van prioriteit Forceren zal de download meteen starten." #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Periodieke controle voor nieuwe versies" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Controleer elke week of er een nieuwe SABnzbd versie beschikbaar is." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "Ook test versies" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Vervang spaties in mapnamen" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Vervang spaties door onderliggende streepjes in namen van mappen." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Vervang punten in mapnamen" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Vervang punten door spaties in namen van mappen." #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Maak compatibel met Windows" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "Voor opslag op servers: gebruik namen die werken op Windows" #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Start webbrowser bij opstarten" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Start de web browser wanneer SABnzbd opstart." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Onderbreek downloaden tijdens nabewerken" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "Onderbreek downloaden tijdens nabewerken." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Negeer samples" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Wat te doen met \"sample\"-bestanden?" #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Verwijderen na download" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "HTTPS certificaatverificatie" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" "Controleer certificaten bij beveiligde verbindingen met indexers en RSS-" "feeds." #: sabnzbd/skintext.py msgid "Server" msgstr "Server" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Nabewerking" #: sabnzbd/skintext.py msgid "Naming" msgstr "Naamgeving" #: sabnzbd/skintext.py msgid "Quota" msgstr "Quotum" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indexering" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Hoeval mag deze maand worden gedownload (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Reset dag" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "Op welke dag van de maand of week (1=maandag) wordt het quotum gereset? " "(Eventueel met hh:mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Automatisch doorgaan" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "" "Moet het downloaden automatisch doorgaan bij het ingaan van het nieuwe " "quotum?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Quotum periode" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "Wordt het quotum elke dag, week of maand gereset?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Controle vóór downloaden" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Probeer de succes kans van een download van te voren in te schatten " "(langzamer!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "SSL-sleutels" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" "Verhoog de prestaties door een eenvoudigere SSL versleuteling toe te passen." #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Maximum aantal pogingen" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Maximaal aantal pogingen per server" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Download afbreken als deze zeker niet kan worden voltooid" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Als tijdens het downloaden duidelijk wordt dat te veel data ontbreekt, breek " "dan de download af" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "Sta integratie met index websites toe" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" "Indexers kunnen beoordelingen meesturen wanneer een download wordt " "toegevoegd en SABnzbd kan de indexer informeren wanneer een download niet " "slaagt." #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Filtering aan" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Verwerk downloads volgens de filter regels" #: sabnzbd/skintext.py msgid "Abort If" msgstr "Afbreken indien" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Anders pauzeren indien" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Video rating" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Audio rating" #: sabnzbd/skintext.py msgid "Spam" msgstr "Spam" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Bevestigd" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Meer duimen omlaag dan omhoog" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Titel trefwoorden" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Door komma's gescheiden lijst" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Balanceren van server belasting" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Schakel balancering uit" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Schakel balancering in" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Schakel balancering met optimalisatie voor IPv6 in" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "Nuttig wanneer een server meer dan één IPv4 of IPv6-adres heeft" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Voeg server toe" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Servernaam" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Poort" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Gebruikersnaam" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Wachtwoord" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Tijdslimiet" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Bewaartijd" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "Beveiligde verbinding met de server" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "Certificaatverificatie" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" "Minimaal: wanneer SSL geactiveerd is, controleer de identiteit van de server " "m.b.v. de certificaten. Strikt: controleer en vereis dat het geldige " "certificaat bij deze servernaam hoort." #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Uit" #: sabnzbd/skintext.py msgid "Minimal" msgstr "Minimaal" #: sabnzbd/skintext.py msgid "Strict" msgstr "Strikt" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 is de hoogste en 100 de laagste prioriteit" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Optioneel" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" "Voor onbetrouwbare servers, deze zullen langer worden genegeerd wanneer ze " "fouten veroorzaken." #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Inschakelen" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Verwijder" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Test Server" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Tellers op nul" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Server instellingen aan het testen..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Bandbreedte" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Verzend groep" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Verzend de groepsnaam naar de server." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Gebruik de server alleen voor deze categorieën" #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" "Geen enkele server heeft de \"Standaard\" categorie. Downloads in de " "wachtrij die geen categorie hebben die ook aan een server is gekoppeld, " "zullen niet worden gedownload." #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Persoonlijke aantekeningen" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Taak toevoegen" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Huidige taken" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "Om de RSS-feed automatisch te verwerken, vink het selectievlakje bij de " "definitie naam aan.
Wanneer een nieuwe feed wordt gedefinieerd, zullen " "alleen nieuwe items gevonden worden en geen bestaande, behalve wanneer je de " "op \"Forceer download\" klikt." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "Zet komma's tussen de URLs" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Uitlezen" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Forceer download" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Filter" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Accepteren" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Titel Bevat Niet" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Titel Bevat" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "Categorie Is" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Minimaal" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Maximaal" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "Vanaf SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "Vanaf Serie SxxEyy" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Geselecteerd" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Verworpen" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Gedownload" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Alle feeds nu uitlezen" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "Stuur een e-mail na het voltooien van elke download" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Nooit" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Altijd" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Alleen bij fouten" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Stuur een e-mail wanneer de harde schijf vol is" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "" "Stuur een e-mail wanneer SABnzbd gestopt is vanwege een volle harde schijf." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Verstuur een e-mail voor RSS" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "" "Verstuur een e-mail wanneer een RSS-feed downloads
aan de wachtrij " "heeft toevoegd." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "SMTP-server" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Het adres van de e-mailserver van je internet provider." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "Ontvanger" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "Adres waarnaar de e-mail verstuurd wordt." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "Afzender" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Wie zou de email gestuurd moeten hebben?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "OPTIONEEL: Account gebruikersnaam" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Wanneer authenticatie nodig is, de gebruikersnaam." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "OPTIONEEL: Account wachtwoord" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Wanneer authenticatie nodig is, het wachtwoord." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Growl meldingen activeren" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Zend meldingen naar Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "" "Alleen gebruiken voor een Growl server op een ander systeem (server:poort)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Server wachtwoord" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Optioneel wachtwoord voor de Growl server" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "NotifyOSD activeren" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Zend meldingen naar NotifyOSD" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Berichtencentrum" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Stuur meldingen naar het Berichtencentrum" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Windows meldingen activeren" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Windows Meldingen" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Prowl berichten activeren" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Een Prowl account is noodzakelijk" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "API-sleutel voor Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Persoonlijke API-sleutel voor Prowl (noodzakelijk)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Pushover meldingen activeren" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Hiervoor is een Pushover account nodig" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Applicatie token" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Applicatie token (verplicht)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Gebrukers sleutel" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Gebrukers sleutel (verplicht)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Apparaten" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Apparaat of apparaten die het bericht moeten ontvangen" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "Noodgeval herhaling" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "Hoevaak moet de notification herhaald worden (in seconden)" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "Einde van noodgeval" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "Hoeveel seconden moet de notificatie herhaald worden" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Pushbullet meldingen activeren" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Hiervoor is een Pushbullet account nodig" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Persoonlijke API-sleutel" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Persoonlijke Pushbullet API-sleutel (verplicht)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Apparaat" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Apparaat dat de berichten moet ontvangen" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "Notificatie Script" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "Notificatie script activeren" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "Voer een zelfgemaakt script uit" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "Welk script moet uitgevoerd worden voor de notificatie?" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" "Indexers kunnen een categorie in de NZB plaatsen en SABnzbd zal die proberen " "toe te passen op onderstaande categorieën. Daarnaast kun je patronen " "invullen in de kolom \"Indexer Categorieën/Groepen\". Gebruik komma's om " "patronen te scheiden. Joker tekens (? en *) zijn toegestaan.
Meer " "informatie op de Wiki." #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Als het pad eindigt met een ster *, dan worden geen aparte download mappen " "gemaakt." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Maplocaties gebaseerd op" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Map/Pad" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "Indexer Categorieën / Groepen" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Serie sorteren" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Serie sorteren aan" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Uitleg" #: sabnzbd/skintext.py msgid "Clear" msgstr "Wissen" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "Filters toepassen" #: sabnzbd/skintext.py msgid "Presets" msgstr "Standaardinstellingen" #: sabnzbd/skintext.py msgid "Example" msgstr "Voorbeeld" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "Film sorteren" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Film sorteren aan" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Zet downloads in aparte mappen" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Beïnvloede categorieën" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Betekenis" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Patroon" #: sabnzbd/skintext.py msgid "Result" msgstr "Resultaat" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Seizoensmappen" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Seizoensmap" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Aflevering-map" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Aflevering-map" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "Downloadnaam als Bestandsnaam" #: sabnzbd/skintext.py msgid "Title" msgstr "Titel" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Film Naam" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Film.Naam" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Film_Naam" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Serie Naam" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Serie.Naam" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Serie_Naam" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Seizoen Nummer" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Aflevering Nummer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Aflevering Naam" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Aflevering.Naam" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Aflevering_Naam" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Bestandsextensie" #: sabnzbd/skintext.py msgid "Extension" msgstr "Extensie" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Volgnummer" #: sabnzbd/skintext.py msgid "Decade" msgstr "Decennium" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Originele bestandsnaam" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "Originele Downloadnaam" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Kleine letters" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEKST" #: sabnzbd/skintext.py msgid "text" msgstr "tekst" #: sabnzbd/skintext.py msgid "file" msgstr "bestand" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Sorteertekst" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Meervoudig label" #: sabnzbd/skintext.py msgid "In folders" msgstr "In mappen" #: sabnzbd/skintext.py msgid "No folders" msgstr "Geen mappen" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Datum sorteren" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Datum sorteren aan" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Toon Naam map" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "Jaar-Maand Mappen" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Dagelijkse Mappen" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "Aanpassen van hoofd- en kleine letters" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Bewerkt resultaat" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Zelden gebruikte opties. Voor betekenis en uitleg, klik op de Help knop om " "naar de Wiki te gaan.
Wijzig hier niet zonder eerst de uitleg op de Wiki " "te lezen. Er kunnen nadelige bijwerkingen optreden.
De standaard " "instellingen staan tussen haakjes." #: sabnzbd/skintext.py msgid "Values" msgstr "Waarden" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Bewerk download details" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Verwijder" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Boven" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Hoger" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Lager" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Onder" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "alles" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "omkeren" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Bestandsnaam" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Onderwerp" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Selectie" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Pauzeer 5 minuten" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Pauzeer 15 minuten" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Pauzeer 30 minuten" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Pauzeer 1 uur" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Pauzeer 3 uur" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Pauzeer 6 uur" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "over" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Vrije ruimte" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Tijdelijke map" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Meervoudige bewerking" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Houdt Shift toets ingedrukt om meer te selecteren" #: sabnzbd/skintext.py msgid "Check all" msgstr "Selecteer alles" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Start SABnzbd opnieuw" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Status en webinterface opties" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Of sleep bestanden in dit venster!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Verbinding met SABnzbd verbroken" #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "Wanneer SABnzbd opnieuw is gestart, gaat dit venster vanzelf weg!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "WAARSCHUWING:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Ophalen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Ververssnelheid" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Instellen voor alle sessies" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Items in wachtrij" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Items in geschiedenis" #: sabnzbd/skintext.py msgid "Date format" msgstr "Datumnotatie" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Extra kolom aan wachtrij toevoegen" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "Extra kolom aan geschiedenis toevoegen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "Pagina" #: sabnzbd/skintext.py msgid "Loading" msgstr "Laden" #: sabnzbd/skintext.py msgid "articles" msgstr "artikelen" #: sabnzbd/skintext.py msgid "Rename" msgstr "Naam" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Wachtrij reparatie" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Toon actieve verbindingen" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Verweesde downloads" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Stuur terug naar de wachtrij" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Alles wissen" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Alles opnieuw proberen" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Haal NZB op via URL" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "NZB uploaden" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Geef eventueel een andere naam" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Formaten: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Verstuur" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Open Informatie URL" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Ingediend. Bedankt!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Niets geselecteerd!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Verwijder alle geselecteerde bestanden" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Toon/verberg voltooide bestanden" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Toon Script resultaat" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Update beschikbaar!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" "\"Local Storage\" (cookies) is uitgeschakeld in je web browser, niet alle " "instellingen zullen worden onthouden." #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "Glitter heeft enkele (nieuwe) functies die je mogelijk aanspreken!" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Aangepast" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "Compacte weergave" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "Weergave in tabs
(wachtrij en geschiedenis apart weergeven)" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Snelheid" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Bevestig verwijderen uit wachtrij" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Bevestig verwijderen uit geschiedenis" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Voor hoe lang of tot wanneer wilt u pauzeren? (in het Engels!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Sorry, het opgegeven kunnen wij niet verwerken. Probeer nogmaals." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Pauzeer..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Ververs" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" "Alle gebruikersnamen, wachtwoorden en API-sleutels worden automatisch " "verwijderd uit het logbestand en de bijgevoegde kopie van je instellingen." #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Sorteer op Leeftijd Oud→Nieuw" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Sorteer op Leeftijd Nieuw→Oud" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Sorteer op Naam A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Sorteer op Naam Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Sorteer op Omvang Klein→Groot" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Sorteer op Omvang Groot→Klein" #: sabnzbd/skintext.py msgid "Uploading" msgstr "Uploaden" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "Verbinding verbreken" #: sabnzbd/skintext.py msgid "Removing job" msgstr "Item aan het verwijderen" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "Items aan het verwijderen" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Vorige" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Volgende" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Wis de volledige geschiedenis?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "JavaScript is nodig voor de werking van Plush!" #: sabnzbd/skintext.py msgid "Options" msgstr "Opties" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Hoeveel minuten pauzeren?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Top menu aan/uit" #: sabnzbd/skintext.py msgid "On Finish" msgstr "Bij lege wachtrij" #: sabnzbd/skintext.py msgid "Sort" msgstr "Sorteren" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Sorteer op Leeftijd (Oud→Nieuw)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Sorteer op Leeftijd (Nieuw→Oud)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Sorteer op Naam (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Sorteer op Naam (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Sorteer op Omvang (Klein→Groot)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Sorteer op Omvang (Groot→Klein)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Verwijderen uit de wachtrij?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Alle mislukte downloads in Geschiedenis opnieuw proberen?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Opschonen" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Max Snelheid" #: sabnzbd/skintext.py msgid "Range" msgstr "Bereik" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Op selectie toepassen" #: sabnzbd/skintext.py msgid "Everything" msgstr "Alles" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Verversingstempo" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Breedte van kader" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "" "Dit voorkomt pagina verversing wanneer de muis aanwijzer in de wachtrij is." #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Geen verversing bij popups" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Ophalen" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Upload: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Voortgang" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Onvoldoende schijfruimte over!" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Vrij (tijdelijke map)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "RUST" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Downloads" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Verwijder geslaagde" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Verwijder alle mislukte items uit de Geschiedenis?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Verwijder mislukte" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Alle mislukte downloads opnieuw proberen?" #: sabnzbd/skintext.py msgid "Links" msgstr "Koppelingen" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Toon %s t/m %s van %s resultaten" #: sabnzbd/skintext.py msgid "No results" msgstr "Geen resultaten" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Eén resultaat" #: sabnzbd/skintext.py msgid "First" msgstr "Eerste" #: sabnzbd/skintext.py msgid "Last" msgstr "Laatste" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "E-mail verzonden!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Melding verzonden" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Opslaan.." #: sabnzbd/skintext.py msgid "Saved" msgstr "Opgeslagen" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "\"NZB toevoegen\" uitklappen" #: sabnzbd/skintext.py msgid "DualView1" msgstr "Dubbel1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "Dubbel2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Weet je zeker dat je SABnzbd wilt herstarten?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Verberg Opties" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Toon Opties" #: sabnzbd/skintext.py msgid "Edit" msgstr "Bewerk" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Te gaan" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "SABnzbd Snelstart Hulp" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "SABnzbd versie" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Vorige" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Server instellingen" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Vul hier de gegevens van je primaire Usenet server in." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Het aantal verbindingen dat je provider toestaat." #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "Bv. 8 of 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Vink dit alleen aan als je provider SSL-verbindingen toestaat." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Klik om de verbinding te testen." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Voorbeeld" #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "Alles ingesteld!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd is actief op de achtergrond." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "Afsluiten van het browservenster zal SABnzbd niet stoppen." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Tip: maak een \"Bladwijzer\" of \"Favoriet\" voor deze locatie, zodat je " "SABnzbd gemakkelijk terug kunt vinden." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Voor meer informatie bekijk de" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Ga naar SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Stop SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Wizard starten" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd wordt aangeboden ZONDER ENIGE VORM VAN GARANTIE.\n" "Het is vrije software en je mag het, onder bepaalde voorwaarden, verder " "verspreiden.\n" "De licentie is de GNU GENERAL PUBLIC LICENSE Versie 2 of (naar eigen keuze) " "een latere versie.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "Om te kunnen downloaden van Usenet, heb je een provider nodig. Je Internet " "bedrijf heeft misschien een server, maar we bevelen een betaalde server aan." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "Heb je nog geen Usenet provider? Wij bevelen %s aan." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Fout bij ophalen TV info (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Hernoemen van %s tot %s mislukt" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Hernoemen van gelijkaardig bestand %s naar %s mislukt" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Servernaam niet te vinden" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Geen toegangsrechten" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "Bestand bestaat niet op de server" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "De server kon de opdracht niet uitvoeren" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "URLGRABBER FATALE FOUT" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Onbruikbaar NZB-bestand" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "URL ophalen mislukt; %s" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "Map \"%s\" bestaat niet." #~ msgid "Error: No secondary interface defined." #~ msgstr "Fout: geen secundaire interface ingesteld." #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Versie van UNRAR wordt niet aanbevolen, download UNRAR van " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgid "Initiating restart...
" #~ msgstr "Begin met herstart...
" #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "Opdracht \"%s\" terug naar de wachtrij" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "Items met een ster '*' worden niet automatisch gedownload." #~ msgid "Not matched" #~ msgstr "Niet geselecteerd" #~ msgid "Downloaded so far" #~ msgstr "Tot nu toe gedaan" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Kan geen verbinding maken met register deel HKEY_CURRENT_USER." #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Kan register sleutel \"%s\" niet lezen" #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Kan register sleutels voor speciale mappen niet lezen" #~ msgid "You have no permisson to use port %s" #~ msgstr "Je hebt geen toestemming om poort %s te gebruiken" #~ msgid "Try again" #~ msgstr "Opnieuw" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "Module \"pyopenssl\" ontbreekt, geen HTTPS mogelijk" #~ msgid "Main packet not found..." #~ msgstr "Hoofdpakket niet gevonden..." #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Verwijderen van nzo van nabewerkingswachtrij mislukt" #~ msgid "View script output" #~ msgstr "Toon script resultaat" #~ msgid "Queued" #~ msgstr "Wacht" #~ msgid "Complete Dir" #~ msgstr "Map voltooid" #~ msgid "Download speed" #~ msgstr "Snelheid" #~ msgid "WARNINGS" #~ msgstr "MELDINGEN" #~ msgid "Add new downloads" #~ msgstr "Opdrachten toevoegen" #~ msgid " or Report ID" #~ msgstr " of Report ID" #~ msgid "Sort by name" #~ msgstr "Op naam" #~ msgid "Sort by age" #~ msgstr "Op leeftijd" #~ msgid "Sort by size" #~ msgstr "Op grootte" #~ msgid "Hide files" #~ msgstr "Verberg bestanden" #~ msgid "Show files" #~ msgstr "Toon bestanden" #~ msgid "Remain/Total" #~ msgstr "Te doen/Totaal" #~ msgid "History Size" #~ msgstr "Totaal" #~ msgid "Show Weblogging" #~ msgstr "Toon weblog info" #~ msgid "Thread" #~ msgstr "Verbinding" #~ msgid "General configuration" #~ msgstr "Algemene instellingen" #~ msgid "Web server authentication" #~ msgstr "Web server authenticatie" #~ msgid "HTTPS Support" #~ msgstr "HTTPS ondersteuning" #~ msgid "Queue auto refresh interval:" #~ msgstr "Verversingsinterval van de Wachtrij" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "Verversingsinterval van het de Wachtrij pagina (sec, 0= geen)." #~ msgid "Disable API-key" #~ msgstr "API-sleutel niet gebruiken" #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "GEBRUIK OP EIGEN RISICO!" #~ msgid "Folder configuration" #~ msgstr "Map instellingen" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Map met gebruikers scripts" #~ msgid "Switches configuration" #~ msgstr "Diverse instellingen" #~ msgid "Processing Switches" #~ msgstr "Nabewerking instellingen" #~ msgid "Enable Quick Check" #~ msgstr "Snelle controle toestaan" #~ msgid "Enable Unrar" #~ msgstr "Unrar toestaan" #~ msgid "Enable built-in unrar functionality." #~ msgstr "Uitpakken van RAR archieven toestaan." #~ msgid "Enable built-in unzip functionality." #~ msgstr "Uitpakken van ZIP archieven toestaan." #~ msgid "Enable Filejoin" #~ msgstr "Samenvoegen van bestanden toestaan" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "Voeg bestanden eindigend met .001, .002 enz. samen tot één file." #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "" #~ "Voeg bestanden eindigend met .001.ts, .002.ts enz. samen tot één file." #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Verwijder artikelen met yEnc crc fouten" #~ msgid "Default Post-Processing" #~ msgstr "Standaard nabewerking" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "Wordt gebruikt wanneer de categorie geen nabewerking opgeeft." #~ msgid "Default User Script" #~ msgstr "Standaard script" #~ msgid "Used when no user script is defined by the category." #~ msgstr "Wordt gebruikt wanneer de categorie geen script opgeeft." #~ msgid "Default Priority" #~ msgstr "Standaard prioriteit" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Wordt gebruikt wanneer de categorie geen prioriteit opgeeft." #~ msgid "Enable MultiCore Par2" #~ msgstr "MultiCore Par2 toestaan" #~ msgid "Other Switches" #~ msgstr "Diverse instellingen" #~ msgid "Do not download" #~ msgstr "Niet downloaden" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Gebruik V23, behalve wanneer persé nodig voor je Internet provider!" #~ msgid "Server configuration" #~ msgstr "Usenet servers" #~ msgid "Backup server" #~ msgstr "Reserve server" #~ msgid "Scheduling configuration" #~ msgstr "Agenda instellen" #~ msgid "Remove" #~ msgstr "Verwijder" #~ msgid "Delete Feed" #~ msgstr "Verwijder" #~ msgid "Skip" #~ msgstr "Overslaan" #~ msgid "User-defined categories" #~ msgstr "Categorieën voor nabewerking" #~ msgid "Defines post-processing and storage." #~ msgstr "Bepalend voor nabewerking en opslag." #~ msgid "Sorting configuration" #~ msgstr "Sorteer instellingen" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Sta sorteren en hernoemen van afleveringen toe." #~ msgid "Generic Sorting" #~ msgstr "Algemeen sorteren" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Sta algemeen sorteren en hernoemen van bestanden toe." #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Sta opslaan van downloads in een eigen map toe." #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Sta sorteren en hernoemen van datum-gebaseerde bestandsnamen toe." #~ msgid "Are you sure you want to delete" #~ msgstr "Weet u zeker dat u wilt verwijderen" #~ msgid "Page" #~ msgstr "Pagina" #~ msgid "Close" #~ msgstr "Sluiten" #~ msgid "Set Pause Interval" #~ msgstr "Set Pauze Interval" #~ msgid "Pause Interval" #~ msgstr "Pauze Interval" #~ msgid "Pause for 12 hours" #~ msgstr "Pauzeer 12 uur" #~ msgid "Pause for 24 hours" #~ msgstr "Pauzeer 24 uur" #~ msgid "Left" #~ msgstr "Over" #~ msgid "Storage" #~ msgstr "Opslag" #~ msgid "Plush Options" #~ msgstr "Plush instellingen" #~ msgid "Hour:Min" #~ msgstr "Uur:Min" #~ msgid "Access" #~ msgstr "Toegang" #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "" #~ "Ik wil SABnzbd kunnen gebruiken vanaf iedere PC in mijn thuisnetwerk." #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Ik wil SABnzbd alleen vanaf deze PC kunnen gebruiken." #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Wachtwoord beveiliging voor SABnzbd (aanbevolen)" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Maak HTTPS (beveiligd) verkeer mogelijk." #~ msgid "Misc" #~ msgstr "Diversen" #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "Start de web browser wanneer SABnzbd opstart." #~ msgid "This field is required." #~ msgstr "Verplicht veld" #~ msgid "Please enter a whole number." #~ msgstr "Vul hier een geheel getal in." #~ msgid "Step One" #~ msgstr "Stap Een" #~ msgid "Step Two" #~ msgstr "Stap Twee" #~ msgid "Step Three" #~ msgstr "Stap Drie" #~ msgid "Step Four" #~ msgstr "Stap Vier" #~ msgid "Step Five" #~ msgstr "Stap Vijf" #~ msgid "KB/s" #~ msgstr "KB/s" #~ msgid " " #~ msgstr " " #~ msgid "Open Source URL" #~ msgstr "Open Source URL" #~ msgid "Click below to test." #~ msgstr "Klik hier onder om te testen." #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Upload: .nzb .rar .zip .gz" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Uitpakken is mislukt, deze bestand(en) ontbreken:" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Gebruik de 12-uren klok (AM/PM)" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Toon tijden in AM/PM notatie (heeft geen invloed op de taakplanner)" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd werkt niet in combinatie met sommige firewall programma's.
\n" #~ "%s
\n" #~ "Het spijt ons, maar we kunnen dit probleem niet oplossen.
\n" #~ "Graag een klacht indienen bij je firewall leverancier.
\n" #~ "
\n" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd heeft een vrije TCP/IP poort nodig voor de interne web " #~ "server.
\n" #~ "Poort %s op %s is geprobeerd, maar het gebruikers account van SABnzbd heeft " #~ "geen toestemming.
\n" #~ "Op OSX en Linux systemen mogen standaard gebruikers alleen poorten boven " #~ "1023 gebruiken.
\n" #~ "
\n" #~ "Start SABnzbd met een ander poort nummer." #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Mogelijk gebruik je ZoneAlarm op Vista.
" #~ msgid "OK" #~ msgstr "OK" #~ msgid "folder" #~ msgstr "map" #~ msgid "Original Foldername" #~ msgstr "Oorspronkelijke mapnaam" #~ msgid "Groups / Indexer tags" #~ msgstr "Groepen / Indexer markeringen" #~ msgid "Server definition" #~ msgstr "Server definitie" #~ msgid "Delete all failed items from History?" #~ msgstr "Verwijder alle mislukte items uit Geschiedenis?" #~ msgid "Purge Failed History" #~ msgstr "Verwijder mislukte items" #~ msgid "Settings" #~ msgstr "Instellingen" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "Probeer deze artikelen opnieuw te downloaden van een reserve server." #~ msgid "Activate an alternative skin." #~ msgstr "Aktiveer een tweede bedieningsstijl (herstart nodig)." #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Geen uitgebreide PAR2 controle als de bestanden 100% in orde zijn." #~ msgid "Get NZB" #~ msgstr "Ophalen" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "Bv. 119 of 563 voor SSL" #~ msgid "Filters" #~ msgstr "Filters" #~ msgid "Check result of unpacking" #~ msgstr "Controleer resultaat van uitpakken" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Controleer resultaat van uitpakken (moet \"uit\" staan voor sommige " #~ "bestandssystemen)." #~ msgid "Add Feed" #~ msgstr "Feed toevoegen" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Uitlezen leest/ververst de huidige feed inhoud. " #~ "Forceer download zal alle geselecteerde NZBs nu downloaden." #~ msgid "RSS Configuration" #~ msgstr "RSS-feed Definities" #~ msgid "New Feed URL" #~ msgstr "URL van nieuwe RSS-feed" #~ msgid "Only for optional servers" #~ msgstr "Alleen voor optionele servers" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Stel alleen een maximaal aantal pogingen in voor optionele servers" #~ msgid "QR Code" #~ msgstr "QR Code" #~ msgid "Feeds" #~ msgstr "Feeds" #~ msgid "Notification classes" #~ msgstr "Bericht types" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "Kies welke bericht types verstuurd moeten worden (geen, één of meer)" #~ msgid "Refer to https://www.oznzb.com/profile" #~ msgstr "Kijk op https://www.oznzb.com/profile" #~ msgid "Automatic Feedback" #~ msgstr "Automatische terugkoppeling" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Deze sleutel is het toegangsbewijs voor de indexer. Kijk op " #~ "https://www.oznzb.com/profile." #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Uitgebreide functionaliteit met waarderingen en extra status informatie " #~ "wanneer gekoppeld aan OZnzb indexer." #~ msgid "Enable OZnzb Integration" #~ msgstr "OZnzb integratie inschakelen" #~ msgid "OZnzb" #~ msgstr "OZnzb" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "Verzend berekende validatie gegevens over downloads naar de indexer." #~ msgid "Email Test Result" #~ msgstr "Test resultaat e-mail" #~ msgid "Email Options" #~ msgstr "E-mailopties" #~ msgid "Email Account Settings" #~ msgstr "E-mail gegevens" #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "Als de SABnzbd opnieuw is opgestart, kun je de bediening via deze koppeling " #~ "bereiken: %s" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "Map waarin zich de nabewerkingsscripts bevinden." #~ msgid "Enable TS Joining" #~ msgstr "Samenvoegen van TS-bestanden toestaan" #~ msgid "Enable Par Cleanup" #~ msgstr "PAR-bestanden opruimen" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Ruim PAR-bestanden op (na succesvolle verificatie/reparatie)." #~ msgid "Do not require the API key." #~ msgstr "Gebruik van de API-sleutel niet afdwingen." #~ msgid "Site API Key" #~ msgstr "API-sleutel van indexer" #~ msgid "Secondary Web Interface" #~ msgstr "Tweede Gebruikersinterface" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Vervang verboden tekens in mapnamen" #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Vervang verboden tekens in mapnamen door gelijkende tekens (anders " #~ "verwijderen)." #~ msgid "SSL type" #~ msgstr "SSL-type" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "WAARSCHUWING: Taak '%s' gepauzeerd vanwege een versleuteld RAR-bestand" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "WAARSCHUWING: Taak '%s' is afgebroken vanwege een versleuteld RAR-bestand" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "CRC-fout in %s (%s -> %s)" #~ msgid "SQL Commit Failed, see log" #~ msgstr "SQL-opslagopdracht mislukt, zie logbestand" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "" #~ "Geen UNRAR-programma gevonden, uitpakken van RAR-bestanden niet mogelijk
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "Geen PAR2-programma gevonden, reparaties niet mogelijk
" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Bestand %s ontbreekt => UNRAR-fout?" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "Uitpakken mislukt, een gewenst bestand is niet uitgepakt" #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Ongeldige par2-bestanden, verificatie of reparatie niet mogelijk" #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Fout bij importeren van OpenSSL-module, probeer NON-SSL" SABnzbd-2.3.2/po/main/pl.po0000644000000000000000000045011713217005051013446 0ustar 00000000000000# Polish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2015-12-28 10:22+0000\n" "Last-Translator: Safihre \n" "Language-Team: Polish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:31+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Nie udało się uruchomić interfejsu WWW" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "Nie znaleziono szablonu: %s, próbuję użyć standardowego szablonu" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "Moduł _yenc... NIE znaleziono!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "Program par2 ... NIE znaleziono!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "Twoja wersja unrar to %s, zalecana jest wersja %s lub wyższa.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "Program unrar ... NIE znaleziono!" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "Program unzip ... NIE znaleziono!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "Program 7za... NIE znaleziono!" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "Nazwa hosta 0.0.0.0 wymaga adresu IPv6 do dostępu z zewnątrz" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "Porty dla HTTP i HTTPS nie mogą być takie same" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "Wyłączono HTTPS z powodu braku plików CERT oraz KEY" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Nie udało się uruchomić interfejsu WWW: " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "Nie można połączyć się z usługą SABHelper" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "Uruchomiono SABnzbd %s" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Ostrzeżenie" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Błąd" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "SABnzbd został wyłączony" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Nie ustawiono nazwy hosta." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "" "Nie ustawiono maksymalnej liczby połączeń. Proszę umożliwić przynajmniej " "jedno połączenie." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Hasło ukryte za ******, proszę wprowadzić je ponownie" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Niewłaściwe dane serwera" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "" "Upłynął limit czasu odpowiedzi: spróbuj włączyć SSL lub połącz się z innym " "portem." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Upłynął limit czasu odpowiedzi." #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Nieprawidłowy adres serwera." #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Serwer przerwał połączenie w trakcie logowania." #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Serwer wymaga podania nazwy użytkownika i hasła." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Połączenie udane!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Błąd połączenia, sprawdź nazwę użytkownika i hasło." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "Zbyt wiele połączeń, proszę wstrzymać pobieranie lub spróbować ponownie " "później" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Nie można określić wyniku połączenia (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Odebrano sygnał %s, zapisywanie i zamykanie programu..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Błąd krytyczny podczas zapisywania stanu" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Próba pobrania NZB z %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Nie udało się zapisać %s" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Nie można utworzyć tymczasowego pliku dla %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Próba ustawienia statusu nieistniejącego serwera %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Błąd w tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Nie udało się wczytać %s" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Nie udało się wczytać %s: %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Powiadomienie testowe" #: sabnzbd/api.py msgid " Resolving address" msgstr " Rozwiązywanie adresu" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Brak" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Domyślne" #: sabnzbd/api.py msgid "unknown" msgstr "nieznany" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Błąd kompilacji wyrażenia regularnego dla wyszukiwania: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "Zbyt mało miejsca na dysku, wymuszanie WSTRZYMANIA" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Dysk pełny! Wstrzymuję pobieranie" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Błąd dysku podczas tworzenia pliku %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Błąd krytyczny w module składającym" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Przerwano, wykryto szyfrowanie" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "UWAGA: Plik z niepożądanym rozszerzeniem wewnątrz pliku RAR \"%s\". " "Niepożądany plik to %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "Niepożądane rozszerzenie w pliku RAR %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Przerwano, wykryto niepożądane rozszerzenie" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "UWAGA: Zadanie \"%s\" zostało wstrzymane z powodu oceny (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "UWAGA: Zadanie \"%s\" zostało przerwane z powodu oceny (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Przerwano, odfiltrowane z powodu oceny (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "Brakuje %s" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "wideo" #: sabnzbd/assembler.py msgid "audio" msgstr "audio" #: sabnzbd/assembler.py msgid "spam" msgstr "spam" #: sabnzbd/assembler.py msgid "passworded" msgstr "zabezpieczone hasłem" #: sabnzbd/assembler.py msgid "downvoted" msgstr "źle oceniane" #: sabnzbd/assembler.py msgid "keywords" msgstr "słowa kluczowe" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Przekroczono limit, wstrzymywanie pobierania" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s nie jest prawidłowym adresem email" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Wymagane jest podanie adresu serwera" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Nie można utworzyć katalogu %s %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Nie można zapisać pliku INI %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Nie można utworzyć kopii zapasowej %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Nieprawidłowo zakodowane hasło %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s nie jest prawidłową wartością w systemie ósemkowym" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "Ścieżka UNC \"%s\" niedozwolona" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Błąd: Długość ścieżki powinna być mniejsza niż %s" #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Błąd: Kolejka nie jest pusta, nie można zmienić katalogu." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "Nie można zapisać bazy danych historii, sprawdź prawa dostępu!" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "Uszkodzona baza danych historii, utworzono w jej miejscu nową, pustą" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "Błąd polecenia SQL, sprawdź logi" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Błąd zamykania bazy danych, sprawdź logi" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Nieprawidłowy log etapu w historii dla %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Błąd dekodowania %s" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Źle zbudowany artykuł yEnc w %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Nieznany błąd podczas dekodowania %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => nie znaleziono na żadnym serwerze, porzucam" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Ukończone" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "Rozpakowano %s plików/katalogów w %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "Nie można odczytać %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Błąd podczas dodawania %s, usuwanie" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Błąd podczas usuwania %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Nie można odczytać obserwowanego katalogu %s" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Wznawianie" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Wstrzymano" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Przed ustawieniem limitu przepustowości należy ustawić maksymalną " "przepustowość" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Serwer %s będzie ignorowany przez %s minut" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Błąd podczas inicjalizacji %s@%s: %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "Zbyt wiele połączeń do serwera %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Prawdopodobne współdzielenie konta" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Błąd logowania do serwera %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Nie można połączyć się z serwerem %s [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "Błąd połączenia %s@%s, komunikat=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Serwer %s wymagania podania nazwy użytkownika i hasła" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Nieobsługiwany błąd w module pobierania" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Wyłączanie" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Błąd połączenia z serwerem pocztowym" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "Błąd połączenia TLS" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "Serwer nie odpowiedział poprawnie na polecenie HELO" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Błąd uwierzytelnienia na serwerze pocztowym" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Nie znaleziono odpowiedniej metody uwierzytelnienia" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "" "Uwierzytelnienie na serwerze pocztowym nie powiodło się z nieznanej przyczyny" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Błąd wysyłania wiadomości email" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Nie udało się zamknąć połączenia z serwerem pocztowym" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "Wiadomość wysłana" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Nie można wysłać wiadomości, brak wymaganych danych" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Brak szablonów wiadomości email w %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Nie podano adresatów, wiadomość nie została wysłana" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Nieprawidłowe kodowanie szablonu wiadomości email %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Nie znaleziono szablonów wiadomości email" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd zgłasza przekroczenie dopuszczalnej zajętości dysku\n" "\n" "Cześć,\n" "\n" "SABnzbd przestał pobierać pliki, ponieważ dysk jest prawie pełen.\n" "Opróżnij trochę miejsca i wznów działanie SABnzbd ręcznie.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "Uwaga: LOCALHOST jest niejednoznaczne, użyj adresu IP." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Nieprawidłowy adres serwera \"%s:%s\"." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Brak klucza sesji" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Błąd: Wymagany klucz sesji" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Błąd: Nieprawidłowy klucz sesji" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "Brak klucza API, należy wprowadzić klucz API z sekcji Konfiguracja->Ogólne " "do zewnętrznego programu:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "Klucz API jest nieprawidłowy, użyj klucza API z sekcji Konfiguracja->Ogólne " "w zewnętrznym programie:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Brak danych uwierzytelniających, wprowadź nazwę użytkownika/hasło z sekcji " "Konfiguracja->Ogólne do zewnętrznego programu:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Wypróbuj naszą nową skórkę, Glitter! Zupełnie nowy, świeży projekt " "zoptymalizowany dla komputerów stacjonarnych i urządzeń przenośnych. Skórkę " "możesz zmienić w sekcji Konfiguracja->Ogólne." #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
SABnzbd został wyłączony.
Zaczekaj około 5 sekund, a " "następnie kliknij na przycisk poniżej.

Odśwież
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Kanał" #: sabnzbd/interface.py msgid "Daily" msgstr "Codziennie" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "Poniedziałek" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Wtorek" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Środa" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Czwartek" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Piątek" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Sobota" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Niedziela" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "wyłączone" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Niezdefiniowany serwer!" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Błędny parametr" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Powrót" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "BŁĄD:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Nieprawidłowa wartość %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "d" #: sabnzbd/misc.py msgid "h" msgstr "g" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Nie można utworzyć katalogu %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "Katalog %s: błąd dostępu do %s" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Nie udało się utworzyć (%s)" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Nie udało się przenieść %s do %s" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Błąd tworzenia klucza i certyfikatu SSL" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Nie można zmienić uprawnień %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Uruchamianie skryptu" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Przetwarzanie końcowe zostało przerwane (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Skrypt" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Zbyt głęboki poziom zagnieżdżenia podczas rozpakowywania [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Łączenie" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Niekompletna sekwencja plików do połączenia" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Łączenie pliku %s nie powiodło się" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Błąd \"%s\" podczas łączenia plików" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Błąd \"%s\" podczas uruchamiania file_join na %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] Połączono %s plików" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Rozpakowywanie nie powiodło się, %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Błąd \"%s\" podczas rozpakowywania plików RAR" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Błąd \"%s\" podczas uruchamiania rar_unpack na %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Usuwanie %s nie powiodło się!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Próba rozpakowania archiwum RAR z użyciem hasła \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Rozpakowywanie nie powiodło się, archiwum wymaga podania hasła" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Rozpakowywanie" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Rozpakuj" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Rozpakowywanie nie powiodło się, nie można znaleźć %s" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "BŁĄD: nie można znaleźć \"%s\"" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Rozpakowywanie nie powiodło się, błąd CRC" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "BŁĄD: nieprawidłowa suma kontrolna CRC w \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "Rozpakowywanie nie powiodło się, błąd zapisu lub zapełniony dysk?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "BŁĄD: błąd zapisu (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Rozpakowywanie nie powiodło się, zbyt długa ścieżka" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "BŁĄD: zbyt długa ścieżka (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Rozpakowywanie nie powiodło się, sprawdź logi" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "BŁĄD: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Bezużyteczny plik RAR" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s plików w %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Błąd \"%s\" podczas uruchamiania unzip() na %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Próba rozpakowania archiwum 7zip z użyciem hasła \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "Zestaw 7zip \"%s\" jest niekompletny, nie można rozpakować" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Nie można rozpakować %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Szybkie sprawdzanie" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Naprawa" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Szybkie sprawdzenie OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Rozpoczynanie naprawy" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "Weryfikacja %s nieudana, choć szybkie sprawdzenie powiodło się!" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Naprawa nie powiodła się, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Błąd %s podczas uruchamiania par2_repair na zestawie %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Błąd \"%s\" podczas wykonywania par2_repair na zestawie %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] PAR2 otrzymał nieprawidłowe opcje, sprawdź ustawienia w sekcji " "Konfiguracja->Przełączniki" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Zweryfikowano w %s, wszystkie pliki prawidłowe" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Zweryfikowano w %s, wymagana naprawa" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "Pobieranie %s bloków..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Pobieranie" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "" "Naprawa nie powiodła się, brak wystarczającej ilości bloków naprawczych " "(brakuje %s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Naprawianie" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Naprawiono w %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Dysk pełny" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Weryfikowanie" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Sprawdzanie" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Serwer nie obsługuje SSL na tym porcie" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Uruchomienie/Wyłączenie" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "Dodano NZB" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Uruchomiono przetwarzanie końcowe" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Zadanie ukończone" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Zadanie nie powiodło się" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Kolejka ukończona" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Inne komunikaty" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Niedostępne" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Błąd wysyłania wiadomości Prowl" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Zła odpowiedź od Pushover (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Nie udało się wysłać wiadomości Pushover" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Zła odpowiedź od Pushbullet (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Nie udało się wysłać wiadomości Pushbullet" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "" "Wykryto kolejkę w starszej wersji, użyj funkcji Status->Naprawa, aby ją " "przekonwertować" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Znaleziono niekompatybilny plik kolejki, nie można kontynuować" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Błąd ładowania %s, wykryto uszkodzony plik" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "Nie udało się ponownie uruchomić NZB po wstępnym sprawdzeniu (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB dodany do kolejki" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Nieznane kodowanie" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Plik %s jest pusty, pomijam" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Nie udało się zaimportować %s plików z %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Niekompletny plik NZB %s" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Nieprawidłowy plik NZB %s, pomijam (powód=%s, linia=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Pusty plik NZB %s" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Ignoruję zduplikowany NZB \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Wstrzymuję zduplikowany NZB \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Przerwano, nie można ukończyć" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "DUPLIKAT" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "ZASZYFROWANY" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "ZA DUŻY" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "NIEKOMPLETNY" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "NIEPOŻĄDANY" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "ODFILTROWANE" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "CZEKAM %s s" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Pobrano w %s ze średnią %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Wiek" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s artykułów było uszkodzonych" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "Brakowało %s artykułów" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s artykułów posiadało niepasujące duplikaty" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s artykułów zostało usuniętych" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Błąd importu %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Ostrzeżenia" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Bezczynny" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Konfiguracja" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Kolejka" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Czyszczenie kolejki" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Historia" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Wyczyść historię" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Ogranicz prędkość" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Wstrzymaj" #: sabnzbd/osxmenu.py msgid "min." msgstr "min." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Wznów" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Przeszukaj obserwowany katalog" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Czytaj wszystkie kanały RSS" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Katalog zakończonych" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Katalog niezakończonych" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Rozwiązywanie problemów" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Uruchom ponownie" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Restart bez logowania" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Zakończ" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Zakolejkuj 10 pierwszych" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Brak" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "10 ostatnich" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Dostępne jest nowe wydanie" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Uruchom kreatora konfiguracji" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Zatrzymywanie..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Problem z" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd wymaga wolnego portu TCP/IP dla wewnętrznego serwera WWW.
\n" " Próbowano użyć portu %s na %s, ale nie jest on dostępny.
\n" " Inny program używa tego portu lub SABnzbd jest już uruchomiony.
\n" "
\n" " Uruchom ponownie SABnzbd używając innego numeru portu." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "" "Jeśli ponownie otrzymasz ten sam błąd, spróbuj zmienić numer portu.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd wymaga prawidłowego adresu hosta dla wewnętrznego serwera " "WWW.
\n" " Podano nieprawidłowy adres.
\n" " Bezpieczne wartości to localhost i 0.0.0.0
\n" "
\n" " Uruchom ponownie SABnzbd używając prawidłowego adresu hosta." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd wykrył dane zapisane w innej wersji SABnzbd
\n" " lecz nie może ponownie użyć tych danych.

\n" " Zaleca się zakończenie pobierania kolejki w innym programie.

\n" " Następnie należy uruchomić SABnzbd z opcją \"--clean\".
\n" " Spowoduje to wymazanie aktualnej kolejki i historii!
\n" " SABnzbd czyta plik \"%s\"." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd nie może znaleźć plików interfejsu WWW w %s.
\n" " Proszę ponownie zainstalować SABnzbd.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd wykrył krytyczny błąd:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd wykrył brak pliku sqlite3.dll.

\n" " Niektóre źle działające programy antywirusowe usuwają ten plik.
\n" " Sprawdź swój program antywirusowy, spróbuj ponownie zainstalować SABnzbd " "i zgłoś problem dostawcy programu antywirusowego.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Naciśnij Klawisz start+R i podaj linię (przykład):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Otwórz okno terminala i podaj linię (przykład):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Program się nie uruchomił!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Błąd krytyczny" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "" "Nie można uruchomić przeglądarki, prawdopodobnie nie została znaleziona" #: sabnzbd/panic.py msgid "Access denied" msgstr "Brak dostępu" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Błąd %s: należy podać prawidłową nazwę użytkownika i hasło." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "Pobieranie może się nie udać, dostępne jedynie %s z wymaganych %s" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Pobieranie nieudane - Dane niedostępne na skonfigurowanych serwerach" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "" "Przetwarzanie końcowe nie zostało uruchomione z powodu nieudanej weryfikacji" #: sabnzbd/postproc.py msgid "Moving" msgstr "Przenoszenie" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "Wysłano %s do kolejki" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Błąd zmiany nazwy \"%s\" na \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Nie udało się przenieść plików" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Uruchamianie skryptu użytkownika %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "Uruchomiono %s" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Kod zakończenia skryptu: %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Więcej" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Przetwarzanie końcowe nie powiodło się dla %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "sprawdź logi" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Pobieranie nie powiodło się" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Czyszczenie %s nie powiodło się." #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Błąd usuwania katalogu roboczego (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Zakończono pobieranie" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Nie można utworzyć ostatecznego katalogu %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Przetwarzanie końcowe" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s} Brak zestawów par2" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Próba weryfikacji SFV" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Weryfikacja niektórych plików względem \"%s\" nie powiodła się" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Poprawnie zweryfikowano z użyciem plików SFV" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "Zabezpieczone hasłem" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Usuwanie %s nie powiodło się" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Hibernacja systemu nie powiodła się" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Wstrzymanie systemu nie powiodło się" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Wyłączenie systemu nie powiodło się" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "Identyfikator indeksera (%s) nie został znaleziony w pliku ocen" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Adres serwera" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "Klucz API" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Nieprawidłowy opis kanału RSS \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Nie udało się pobrać RSS z %s: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Brak poprawnego uwierzytelnienia dla kanału %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "Błąd po stronie serwera (kod: %s); nie udało się pobrać %s z %s" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "Serwer %s używa niezaufanego certyfikatu HTTPS" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "Kanał RSS %s był pusty" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Niekompatybilny kanał" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Znaleziono pusty wpis RSS (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Pokaż interfejs" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Otwórz katalog zakończonych" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Zakończ" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Pozostało" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Dodaj NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Zły harmonogram %s o %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Nieznane działanie: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Harmonogram dla nieistniejącego serwera %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Pobierz" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Połącz pliki" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Źródło" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Serwery" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Niepowodzenie" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Nieudane" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "Oczekuje" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Naprawianie..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Rozpakowywanie..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Przenoszenie..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Wykonywanie skryptu..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Pobieranie dodatkowych bloków..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Szybkie sprawdzanie..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Weryfikowanie..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Pobieranie" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Częstotliwość" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Działanie" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Argumenty" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Zadanie" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "wyłącz serwer" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "włącz serwer" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Ogranicz prędkość" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Wstrzymaj wszystkie" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Wstrzymaj przetwarzanie końcowe" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Wznów przetwarzanie końcowe" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Czytaj kanały RSS" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Usuń nieudane zadania" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Usuń ukończone zadania" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Wstrzymaj zadania o niskim priorytecie" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Wstrzymaj zadania o normalnym priorytecie" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Wstrzymaj zadania o wysokim priorytecie" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Wznów zadania o niskim priorytecie" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Wznów zadania o normalnym priorytecie" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Wznów zadania o wysokim priorytecie" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Włącz zarządzanie limitem" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Wyłącz zarządzanie limitem" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Brak" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Bardzo niski" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Średni" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normalny" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Wysoki" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Awaryjny" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Niski" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "MB" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "GB" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "godzina" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "godziny" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "minuta" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "minut" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "sekunda" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "sekund" #: sabnzbd/skintext.py msgid "day" msgstr "dzień" #: sabnzbd/skintext.py msgid "days" msgstr "dni" #: sabnzbd/skintext.py msgid "week" msgstr "tydzień" #: sabnzbd/skintext.py msgid "Month" msgstr "Miesiąc" #: sabnzbd/skintext.py msgid "Year" msgstr "Rok" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Dzień miesiąca" #: sabnzbd/skintext.py msgid "This week" msgstr "Ten tydzień" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Ten miesiąc" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "Dzisiaj" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Razem" #: sabnzbd/skintext.py msgid "on" msgstr "włączone" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parametry" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Wersja Pythona" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Strona projektu" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "lub" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Host" #: sabnzbd/skintext.py msgid "Comment" msgstr "Komentarz" #: sabnzbd/skintext.py msgid "Send" msgstr "Wyślij" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Anuluj" #: sabnzbd/skintext.py msgid "Other" msgstr "Inne" #: sabnzbd/skintext.py msgid "Report" msgstr "Zgłoś" #: sabnzbd/skintext.py msgid "Video" msgstr "Wideo" #: sabnzbd/skintext.py msgid "Audio" msgstr "Audio" #: sabnzbd/skintext.py msgid "Not used" msgstr "Nieużywane" #: sabnzbd/skintext.py msgid "or less" msgstr "lub mniej" #: sabnzbd/skintext.py msgid "Log in" msgstr "" #: sabnzbd/skintext.py msgid "Log out" msgstr "" #: sabnzbd/skintext.py msgid "Remember me" msgstr "" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "Automatyczne narzędzie do pobierania z Usenetu" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Zapisz" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Czy jesteś pewien?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Usunąć wszystkie pobrane pliki?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Start" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Konfiguracja" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Status" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Pomoc" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Forum" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Ogólne" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Katalogi" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Przełączniki" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Harmonogram" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Powiadomienia" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "Email" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Kategorie" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Sortowanie" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Specjalne" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Szukaj" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Katalog pobierania" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "ZATRZYMANE" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "%s artykułów (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Obciążenie" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Nowe wydanie %s dostępne na" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Czy na pewno wyłączyć SABnzbd?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Dodaj" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Dodaj plik" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Kategoria" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Przetwarzanie" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Priorytet" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Napraw" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Rozpakuj" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Usuń" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "N" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "U" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Wymuś" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Stop" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "Wprowadź URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "Po ukończeniu kolejki" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Wyłącz komputer" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "Uśpij komputer" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Hibernuj komputer" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Wyłącz SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Limit prędkości" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Wstrzymaj na" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Kolejność" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Nazwa" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "ETA" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "Wiek" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Usuń" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Ponów" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Działania" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Skrypty" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Usunąć wszystkie obiekty z kolejki?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Wyczyść NZB" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Wyczyść NZB i usuń pliki" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Ponów wszystkie nieudane zadania" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Usuń NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Usuń NZB i pliki" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "z" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Brakujące artykuły" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Pozostało limitu" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "ręcznie" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Resetuj limit" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Usunąć z historii wszystkie ukończone pliki?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Ukryj szczegóły" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Pokaż szczegóły" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Pokaż nieudane" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Pokaż wszystko" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Rozmiar" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Wyczyść nieudane NZB" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Wyczyść nieudane NZB i usuń pliki" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Wyczyść ukończone NZB" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "Opcjonalne dodatkowe NZB" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Ścieżka" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Ponów wszystkie nieudane" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Ponów wszystkie" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Wirus/spam" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "Poza okresem przechowywania" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Inny problem" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Wymuś rozłączenie" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Nastąpi wysłanie testowej wiadomości na twoje konto." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Pokaż logi" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Przetestuj email" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Logowanie" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Błędy/Ostrzeżenia" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ Informacje" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ Debugowanie" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Połączenia" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Ostatnie ostrzeżenia" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "wyczyść" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Odblokuj" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Identyfikator artykułu" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Zestaw plików" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Kiedy" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Typ" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Włączony" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Panel główny" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Połączenie nie powiodło się!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Lokalny adres IPv4" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Publiczny adres IPv4" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "Adres IPv6" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Serwer DNS" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "Model procesora" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "Wydajność systemu (Pystone)" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Szybkość zapisu w katalogu pobierania" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Szybkość zapisu w katalogu zakończonych" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Szybkość zapisu" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "Zapis nie powiódł się. Sprawdź uprawnienia katalogu do zapisu." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Kliknij znajdujący się poniżej przycisk Powtórz test, aby zmierzyć" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Powtórz test" #: sabnzbd/skintext.py msgid "Config File" msgstr "Plik konfiguracyjny" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Użyta pamięć podręczna" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "SABnzbd zostanie zrestartowane.
Użyj tej funkcji jeśli uważasz, że " "program ma problemy ze stabilnością.
Pobieranie zostanie wstrzymane " "przed restartem i wznowione po ponownym uruchomieniu." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" #: sabnzbd/skintext.py msgid "Advanced" msgstr "" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "W katalogu pobierania istnieją porzucone zadania.
Możesz je usunąć " "(razem z plikami) lub wysłać z powrotem do kolejki." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "Przycisk \"Napraw\" ponownie uruchomi SABnzbd i spowoduje kompletne
odtworzenie zawartości kolejki, z zachowaniem już pobranych plików.
Kolejność elementów kolejki zostanie zmieniona." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Nie zachowano zmian, zostaną one utracone." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Włącz unzip" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "Włącz 7zip" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" #: sabnzbd/skintext.py msgid "Version" msgstr "Wersja" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Czas działania" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Zapasowy" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Przeczytaj o tym w Wiki!" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Restartowanie SABnzbd..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Zmiany wymagają restartu SABnzbd!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "Serwer WWW SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "Adres hosta SABnzbd" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Host, na którym ma nasłuchiwać SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "Port SABnzbd" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Port, na którym ma nasłuchiwać SABnzbd" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Interfejs WWW" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Wybierz skórkę" #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "Użytkownik SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Opcjonalna nazwa użytkownika" #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "Hasło SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Opcjonalne hasło" #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "Włącz HTTPS" #: sabnzbd/skintext.py msgid "not installed" msgstr "nie zainstalowane" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Włącz dostęp do interfejsu przez HTTPS" #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "Port HTTPS" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "" "Jeśli pole będzie puste, standardowy port będzie obsługiwał tylko HTTPS" #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "Certyfikat HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Nazwa pliku lub ścieżka do certyfikatu HTTPS" #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "Klucz HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Nazwa pliku lub ścieżka do klucza HTTPS" #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "Łańcuch certyfikatów HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Nazwa pliku lub ścieżka do łańcucha certyfikatów HTTPS" #: sabnzbd/skintext.py msgid "Tuning" msgstr "Strojenie" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "Interwał sprawdzania RSS" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Interwał sprawdzania (w minutach, co najmniej 15). Nieużywany podczas " "korzystania z harmonogramu!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Maksymalna przepustowość łącza" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Procent przepustowości łącza" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "" "Jaki procent dostępnej przepustowości ma wykorzystywać SABnzbd, np. 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Limit pamięci podręcznej artykułów" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Umieszcza artykuły w pamięci podręcznej, aby ograniczyć częstotliwość " "dostępu do dysku.
W bajtach, opcjonalnie z przyrostkiem K, M, G. " "Przykład: \"64M\" lub \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Lista czyszczenia" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Lista rozszerzeń plików, które mają zostać usunięte po pobraniu.
Na " "przykład: nfo lub nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Zapisz zmiany" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Resetuj" #: sabnzbd/skintext.py msgid "Language" msgstr "Język" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Wybierz język interfejsu WWW" #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "Ten klucz umożliwi innym programom dostęp do SABnzbd" #: sabnzbd/skintext.py msgid "NZB Key" msgstr "Klucz NZB" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "Ten klucz umożliwi innym programom dodawanie plików NZB do SABnzbd" #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Utwórz nowy klucz" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "Kod QR klucza API" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Lista zakresów sieci lokalnych" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Wszystkie lokalne adresy sieciowe zaczynają się od tych prefiksów (często " "\"192.168.1.\")" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Dostęp z zewnątrz" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" #: sabnzbd/skintext.py msgid "No access" msgstr "Brak dostępu" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Dodawanie plików NZB " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (bez Konfiguracji)" #: sabnzbd/skintext.py msgid "Full API" msgstr "Pełne API" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Pełny interfejs WWW" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "UWAGA: Katalogi zostaną automatycznie utworzone po zapisaniu zmian. " "Możesz użyć ścieżek absolutnych, aby wskazać lokalizację poza domyślnym " "katalogiem bazowym." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Katalogi użytkownika" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Przeglądaj" #: sabnzbd/skintext.py msgid "In" msgstr "W" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Tymczasowy katalog pobierania" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Miejsce przechowywania nieprzetworzonych plików.
Można zmienić tylko " "kiedy kolejka jest pusta." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Minimalna ilość wolnego miejsca w tymczasowym katalogu pobierania" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Automatycznie wstrzymaj pobieranie, jeśli pozostanie mniej miejsca niż " "podano.
W bajtach, opcjonalnie z przyrostkiem K, M, G, T. Przykład: " "\"800M\" lub \"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Katalog dla ukończonych plików" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Miejsce przechowywania ukończonych, przetworzonych plików.
Może " "zostać zmienione przez ustawienia kategorii." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Uprawnienia dla ukończonych plików" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Ustawienia podane uprawnienia dla pobranych plików/katalogów.
W " "notacji ósemkowej. Przykład: \"775\" lub \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Obserwowany katalog" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Katalog monitorowany w poszukiwaniu plików .nzb.
Skanowane są " "również pliki .zip, .rar oraz .tar.gz." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Częstotliwość skanowania katalogu obserwowanego" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Ilość sekund pomiędzy kolejnymi skanami w poszukiwaniu plików .nzb" #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Katalog szablonów email" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "" "Katalog zawierający zdefiniowane przez użytkownika szablony powiadomień email" #: sabnzbd/skintext.py msgid "Password file" msgstr "Plik z hasłami" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Plik zawierający wszystkie hasła, które będą używane do rozpakowywania " "zaszyfrowanych plików RAR" #: sabnzbd/skintext.py msgid "System Folders" msgstr "Katalogi systemowe" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Katalog administracyjny" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Lokalizacja bazy danych administracyjnych i historycznych kolejki.
Można zmienić tylko kiedy kolejka jest pusta." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "Dane nie zostaną przeniesione. Wymaga restartu SABnzbd!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Katalog logów" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "Lokalizacja logów SABnzbd.
Wymaga restartu SABnzbd!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr "Katalog kopii zapasowych .nzb" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Miejsce przechowywania plików .nzb" #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Domyślny katalog bazowy" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Pobierz wszystkie pliki par2" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Włącz rekursywne rozpakowywanie" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Rozpakowuj archiwa (rar, zip, 7z) wewnątrz archiwów" #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Ignoruj foldery wewnątrz archiwów" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Wszystkie pliki zostaną rozpakowane do jednego folderu" #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Pobieraj artykuły tylko dla pierwszego pliku w kolejce" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Włącz, aby zmniejszyć użycie pamięci. Wyłącz, aby zapobiec blokowaniu " "kolejki przez powolne zadania." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Przetwarzanie końcowe tylko dla zweryfikowanych zadań" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "" "Uruchom przetwarzanie końcowe tylko dla zadań, które zostały sprawdzone przy " "użyciu PAR2" #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Działanie dla zaszyfrowanych plików RAR" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "Jeśli wybrano \"Wstrzymaj\", będzie trzeba ustawić hasło i wznowić zadanie" #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Działanie dla duplikatów" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Wykryj zduplikowane odcinki seriali" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Odrzuć" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Przerwij" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Działanie dla niepożądanych rozszerzeń" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "" "Działanie, które zostanie podjęte po wykryciu w pliku RAR niepożądanego " "rozszerzenia" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Niepożądane rozszerzenia" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Lista niepożądanych rozszerzeń. Przykład: exe lub exe, com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Włącz sprawdzanie przy użyciu SFV" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Wykonuj dodatkową weryfikację na podstawie plików SFV" #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Skrypty użytkownika mogą oznaczyć zadanie jako nieudane" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Jeśli skrypt użytkownika zwróci niezerowy kod zakończenia, zadanie zostanie " "oznaczone jako nieudane" #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "Użyj alternatywnego NZB w razie niepowodzenia" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "" "Niektóre serwery udostępniają alternatywne NZB, kiedy pobieranie kończy się " "niepowodzeniem" #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Włącz zmianę nazw katalogów" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Używaj tymczasowych nazw podczas przetwarzania końcowego. Należy wyłączyć tę " "opcję, jeśli system nie obsługuje jej prawidłowo." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Skrypt użytkownika przed zakolejkowaniem" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Uruchamiany zanim plik NZB zostanie umieszczony w kolejce" #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Dodatkowe parametry PAR2" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Parametry nice" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "Parametry IONice" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Rozłącz przy pustej kolejce" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "Rozłącz serwer(y) Usenet kiedy kolejka jest pusta lub wstrzymana" #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Sortuj według wieku" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Automatycznie sortuj pozycje według wieku (średniego)" #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Sprawdzaj aktualizacje" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Sprawdzaj co tydzień dostępność nowych wydań SABnzbd" #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "także wydania testowe" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Zastąp spacje w nazwach katalogów" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Zastąp spacje w nazwach katalogów podkreśleniami" #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Zastąp kropki w nazwach katalogów" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Zastąp kropki w nazwach katalogów spacjami" #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Kompatybilność z Windows" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "Dla serwerów: zapewnij zgodność nazw z Windows" #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Uruchom przeglądarkę podczas uruchamiania" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Uruchom domyślną przeglądarkę podczas uruchamiania SABnzbd" #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Wstrzymaj pobieranie podczas przetwarzania końcowego" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Wstrzymuje pobieranie po rozpoczęciu przetwarzania końcowego i wznawia je po " "zakończeniu" #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Działanie dla próbek" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "" "Działania, które zostaną podjęte dla plików próbek (np. próbek wideo)" #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Usuń po pobraniu" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" #: sabnzbd/skintext.py msgid "Server" msgstr "Serwer" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Przetwarzanie końcowe" #: sabnzbd/skintext.py msgid "Naming" msgstr "Nazwy" #: sabnzbd/skintext.py msgid "Quota" msgstr "Limit pobierania" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indeksowanie" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Ile danych można pobrać w miesiącu (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Dzień resetu" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "W którym dniu miesiąca lub tygodnia (1=poniedziałek) twój dostawca resetuje " "limit pobierania (opcjonalnie z gg:mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Automatyczne wznawianie" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "Czy pobieranie powinno zostać automatycznie wznowione w dniu resetu" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Okres limitu" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "Czy limit jest kasowany dziennie, tygodniowo czy miesięcznie?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Sprawdź przed pobraniem" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Spróbuj przewidzieć, czy pobieranie będzie udane przed jego rozpoczęciem " "(wolne!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Maksymalna ilość prób" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Maksymalna ilość prób połączenia z serwerem" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Przerwij zadania, które nie mogą zostać ukończone" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Jeśli podczas pobierania okaże się, że brakuje zbyt dużej ilości danych, " "przerwij zadanie" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Włącz filtrowanie" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Wykonuj działania na zadaniach w oparciu o reguły filtrowania" #: sabnzbd/skintext.py msgid "Abort If" msgstr "Przerwij, jeśli" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Bądź wstrzymaj, jeśli" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Ocena wideo" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Ocena audio" #: sabnzbd/skintext.py msgid "Spam" msgstr "Spam" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Potwierdzone" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Więcej ocen negatywnych niż pozytywnych" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Słowa kluczowe w tytule" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Lista wartości oddzielonych przecinkami" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Równoważenie obciążenia serwerów" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Zapobiegaj równoważeniu obciążenia" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Zezwól na równoważenie obciążenia" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Zezwól na równoważenie obciążenia, preferując IPv6" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "Przydatne, gdy serwer ma więcej niż jeden adres IPv4/IPv6" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Dodaj serwer" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Opis serwera" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Port" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Nazwa użytkownika" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Hasło" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Limit czasu odpowiedzi" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Czas przechowywania" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Wyłączone" #: sabnzbd/skintext.py msgid "Minimal" msgstr "" #: sabnzbd/skintext.py msgid "Strict" msgstr "" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 oznacza najwyższy priorytet, 100 - najniższy" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Opcjonalny" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Włączony" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Usuń serwer" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Testuj serwer" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Wyzeruj liczniki" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Testuję serwer..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Przepustowość" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Wyślij GROUP" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Wyślij polecenie GROUP przed żądaniem artykułu" #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Używaj tego serwera tylko dla tych kategorii" #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Notatki osobiste" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Dodaj harmonogram" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Obecne harmonogramy" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "Pole wyboru obok nazwy kanału musi być zaznaczone, aby kanał był włączony i " "automatycznie sprawdzany w poszukiwaniu nowych wpisów.
Po dodaniu " "kanału będą pobierane tylko nowe wpisy - żaden istniejący już w kanale RSS " "wpis nie zostanie pobrany, chyba że klikniesz przycisk \"Wymuś pobranie\"." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Pobierz kanał" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Wymuś pobranie" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Filtr" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Akceptuj" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Odrzuć" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Wymaga" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "WymagaKat" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Przynajmniej" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Najwyżej" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "Od SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Dopasowano" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Nie dopasowano" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Pobrane" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Czytaj teraz wszystkie kanały" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "Powiadomienia email po zakończeniu zadania" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Nigdy" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Zawsze" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Tylko błędy" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Powiadomienie o pełnym dysku" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "Powiadom, kiedy dysk jest pełen, a SABnzbd wstrzymany" #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Powiadomienia RSS" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "Powiadom, kiedy kanał RSS dodaje zadanie do kolejki" #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "Serwer SMTP" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Ustaw serwer swojego ISP dla poczty wychodzącej" #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "Adresat wiadomości email" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "Adres email, na który będą wysyłane powiadomienia" #: sabnzbd/skintext.py msgid "Email Sender" msgstr "Nadawca wiadomości email" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Kto powinien być nadawcą wiadomości email?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "OPCJONALNA nazwa konta" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Nazwa konta dla kont z uwierzytelnieniem" #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "OPCJONALNE hasło do konta" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Hasło dla kont z uwierzytelnieniem" #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Włącz Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Wysyłaj powiadomienia Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Tylko dla zdalnych serwerów Growl (host:port)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Hasło serwera" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Opcjonalne hasło dla serwera Growl" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "Włącz NotifyOSD" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Wysyłaj powiadomienia do NotifyOSD" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Centrum powiadomień" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Wysyłaj powiadomienia do centrum powiadomień" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Włącz powiadomienia Windows" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Powiadomienia Windows" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Włącz powiadomienia Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Wymaga konta Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "Klucz API Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Prywatny klucz API Prowl (wymagany)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Włącz powiadomienia Pushover" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Wymaga konta Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Token aplikacji" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Token aplikacji (wymagany)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Klucz użytkownika" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Klucz użytkownika (wymagany)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Urządzenie(-a)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Urządzenie(-a), do którego(-ych) mają być wysyłane powiadomienia" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Włącz powiadomienia Pushbullet" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Wymaga konta Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Prywatny klucz API" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Prywatny klucz API Pushbullet (wymagany)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Urządzenie" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Urządzenie, do którego mają być wysyłane powiadomienia" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Zakończenie ścieżki znakiem gwiazdki (*) zapobiegnie tworzeniu katalogów dla " "zadań." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Ścieżki względne w stosunku do" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Katalog/Ścieżka" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Sortowanie seriali" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Włącz sortowanie TV" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Zastępowane ciągi" #: sabnzbd/skintext.py msgid "Clear" msgstr "Wyczyść" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "" #: sabnzbd/skintext.py msgid "Presets" msgstr "Predefiniowane" #: sabnzbd/skintext.py msgid "Example" msgstr "Przykład" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Włącz sortowanie filmów" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Trzymaj niesklasyfikowane zadania w dodatkowych katalogach" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Dotyczy kategorii" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Znaczenie" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Ciąg" #: sabnzbd/skintext.py msgid "Result" msgstr "Wynik" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "Katalog sezonu 1x05" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "Katalog sezonu S01E05" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "Katalog odcinka 1x05" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "Katalog odcinka S01E05" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Tytuł" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Tytuł filmu" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Tytuł.Filmu" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Tytuł_Filmu" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Tytuł serialu" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Tytuł.serialu" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Tytuł_serialu" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Numer sezonu" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Numer odcinka" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Tytuł odcinka" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Tytuł.odcinka" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Tytuł_odcinka" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Rozszerzenie pliku" #: sabnzbd/skintext.py msgid "Extension" msgstr "Rozszerzenie" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Numer fragmentu" #: sabnzbd/skintext.py msgid "Decade" msgstr "Dekada" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Oryginalna nazwa pliku" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Małe litery" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEKST" #: sabnzbd/skintext.py msgid "text" msgstr "tekst" #: sabnzbd/skintext.py msgid "file" msgstr "plik" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Wzorzec sortowania" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Etykieta wieloczęściowa" #: sabnzbd/skintext.py msgid "In folders" msgstr "W katalogach" #: sabnzbd/skintext.py msgid "No folders" msgstr "Brak katalogów" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Sortowanie według daty" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Włącz sortowanie według daty" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Katalog z tytułem serialu" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "Katalogi rok-miesiąc" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Katalogi dzienne" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "z dostosowaniem wielkości liter" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Przetworzony ciąg" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Rzadko używane opcje. Jeśli chcesz się dowiedzieć, co oznaczają, kliknij " "przycisk Pomoc, aby przejść do strony Wiki.
Nie zmieniaj tych opcji bez " "uprzedniego przeczytania Wiki, ponieważ niektóre mają poważne skutki " "uboczne.
Domyślne wartości zostały umieszczone w nawiasach." #: sabnzbd/skintext.py msgid "Values" msgstr "Wartości" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Edytuj szczegóły NZB" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Usuń" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Na górę" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Wyżej" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Niżej" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Na dół" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Wszystko" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Odwróć" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Nazwa pliku" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Temat" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Zaznaczenie" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Wstrzymaj na 5 minut" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Wstrzymaj na 15 minut" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Wstrzymaj na 30 minut" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Wstrzymaj na 1 godzinę" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Wstrzymaj na 2 godziny" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Wstrzymaj na 6 godzin" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "pozostało" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Wolne miejsce" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Folder tymczasowy" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Operacje na wielu" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Przytrzymaj klawisz Shift, aby zaznaczyć zakres" #: sabnzbd/skintext.py msgid "Check all" msgstr "Sprawdź wszystkie" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Uruchom ponownie SABnzbd" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Stan i opcje interfejsu" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Lub przeciągnij i upuść pliki do okna!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Utracono połączenie z SABnzbd..." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "" "W razie ponownego uruchomienia SABnzbd ten ekran zniknie automatycznie!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "UWAGA:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Pobierz" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Częstotliwość odświeżania" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Użyj globalnych ustawień interfejsu" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Limit wyświetlanych pozycji kolejki" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Limit wyświetlanych pozycji historii" #: sabnzbd/skintext.py msgid "Date format" msgstr "Format daty" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Dodatkowa kolumna kolejki" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "strona" #: sabnzbd/skintext.py msgid "Loading" msgstr "Ładowanie" #: sabnzbd/skintext.py msgid "articles" msgstr "artykułów" #: sabnzbd/skintext.py msgid "Rename" msgstr "Zmień nazwę" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Naprawa kolejki" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Pokaż aktywne połączenia" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Porzucone zadania" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Wyślij z powrotem do kolejki" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Usuń wszystko" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Ponów wszystkie" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Pobierz NZB z URL" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "Wczytaj NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Opcjonalnie podaj nazwę pliku" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Formaty: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Wyślij" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Otwórz URL informacyjny" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Wysłano. Dzięki!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Nic nie zaznaczono!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Usuń wszystkie zaznaczone pliki" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Pokaż/ukryj ukończone pliki" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Zobacz log skryptu" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Dostępna aktualizacja!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Własny" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Prędkość" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Potwierdzaj usuwanie z kolejki" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Potwierdzaj usuwanie z historii" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Jak długo lub do kiedy chcesz wstrzymać? (po angielsku!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Przykro mi, nie rozumiem. Spróbuj ponownie." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Wstrzymaj na..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Odśwież" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Sortuj według wieku Najstarsze→Najnowsze" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Sortuj według wieku Najnowsze→Najstarsze" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Sortuj według nazwy A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Sortuj według nazwy Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Sortuj według rozmiaru Najmniejsze→Największe" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Sortuj według rozmiaru Największe→Najmniejsze" #: sabnzbd/skintext.py msgid "Uploading" msgstr "" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "" #: sabnzbd/skintext.py msgid "Removing job" msgstr "" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Wstecz" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Dalej" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Wyczyścić historię?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Plush wymaga włączenia obsługi JavaScript!" #: sabnzbd/skintext.py msgid "Options" msgstr "Opcje" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Na ile minut wstrzymać?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Górne menu" #: sabnzbd/skintext.py msgid "On Finish" msgstr "Po zakończeniu" #: sabnzbd/skintext.py msgid "Sort" msgstr "Sortuj" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Sortuj według wieku (Najstarsze→Najnowsze)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Sortuj według wieku (Najnowsze→Najstarsze)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Sortuj według nazwy (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Sortuj według nazwy (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Sortuj według rozmiaru (Najmniejsze→Największe)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Sortuj według rozmiaru (Największe→Najmniejsze)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Wyczyścić kolejkę?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Ponowić wszystkie nieudane zadania z historii?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Wyczyść" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Limit prędkości" #: sabnzbd/skintext.py msgid "Range" msgstr "Zakres" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Zastosuj do zaznaczonych" #: sabnzbd/skintext.py msgid "Everything" msgstr "Wszystko" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Częstotliwość odświeżania" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Szerokość kontenera" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "Blokuje odświeżanie zawartości po najechaniu kursorem na kolejkę" #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Zablokuj odświeżanie podczas wskazywania" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Wczytaj" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Wczytaj: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Postęp" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Niewystarczająca ilość miejsca na dysku do ukończenia pobierania!" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Wolne (tymczasowo)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "BEZCZYNNY" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Pobieranie" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Usuwanie zakończone" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Usunąć z historii wszystkie nieudane pliki?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Usuwanie nie powiodło się" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Ponowić wszystkie nieudane zadania?" #: sabnzbd/skintext.py msgid "Links" msgstr "Odnośniki" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Wyświetlanie wyników %s-%s z %s" #: sabnzbd/skintext.py msgid "No results" msgstr "Brak wyników" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Pokazuję jeden wynik" #: sabnzbd/skintext.py msgid "First" msgstr "Początek" #: sabnzbd/skintext.py msgid "Last" msgstr "Koniec" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "Wysłano email!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Wysłano powiadomienie!" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Zapisywanie..." #: sabnzbd/skintext.py msgid "Saved" msgstr "Zapisano" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Pokaż/ukryj panel dodawania NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "DualView1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "DualView2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Czy na pewno zrestartować SABnzbd?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Ukryj opcje edycji" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Pokaż opcje edycji" #: sabnzbd/skintext.py msgid "Edit" msgstr "Edycja" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Pozostało" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "Szybki kreator konfiguracji SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "Wersja SABnzbd" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Wstecz" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Szczegóły serwera" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Podaj szczegóły swojego głównego dostawcy Usenet" #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Ilość połączeń dopuszczanych przez twojego dostawcę" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "np. 8 lub 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Zaznacz tylko jeśli twój dostawca zezwala na połączenia SSL" #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Kliknij, aby przetestować wprowadzone dane" #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Np." #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "Konfiguracja ukończona!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd będzie uruchomiony w tle." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "Zamknięcie okna przeglądarki lub karty NIE zamknie SABnzbd." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Zalecamy dodanie tej strony do zakładek i używanie tej zakładki do " "późniejszego dostępu do SABnzbd uruchomionego w tle." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Dalszą pomoc można uzyskać na naszej" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Przejdź do SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Wyjście z SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Uruchom kreatora konfiguracji" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd wydawany jest ABSOLUTNIE BEZ ŻADNEJ GWARANCJI.\n" "To jest wolne oprogramowanie i mile widziane jest dalsze rozpowszechnianie " "go przez ciebie na określonych warunkach.\n" "Program jest wydawany na licencji GNU GENERAL PUBLIC LICENSE w wersji 2 lub " "(według twojego wyboru) którejś z późniejszych wersji.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "Pobieranie z Usenetu wymaga dostępu do dostawcy. Twój ISP może umożliwiać " "dostęp, aczkolwiek zalecany jest dostawca klasy premium." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "Nie masz dostawcy Usenet? Polecamy spróbować %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Błąd pobierania informacji TV (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Nie udało się zmienić nazwy %s na %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Nie udało się zmienić nazwy podobnego pliku %s na %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Nie udało się rozwiązać nazwy serwera" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Dostęp zabroniony" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "Działanie modułu pobierania URL zostało przerwane" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Bezużyteczny plik NZB" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "Pobieranie URL nie powiodło się; %s" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "Błąd CRC w %s (%s -> %s)" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "Folder \"%s\" nie istnieje" #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Twoja wersja programu UNRAR jest niezalecana, pobierz nową z " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgid "Initiating restart...
" #~ msgstr "Inicjuję restart...
" #~ msgid "Downloaded so far" #~ msgstr "Dotychczas pobrano" #~ msgid "SQL Commit Failed, see log" #~ msgstr "Błąd wykonania polecenia SQL, sprawdź logi" #~ msgid "Not matched" #~ msgstr "Nie dopasowano" #~ msgid "Try again" #~ msgstr "Spróbuj ponownie" #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Nie można otworzyć klucza rejestru \"%s\"." #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Rozpakowywanie nie powiodło się, brak następujących plików:" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "" #~ "Rozpakowywanie nie powiodło się, oczekiwany plik nie został wypakowany" #~ msgid "OK" #~ msgstr "OK" #~ msgid "Get NZB" #~ msgstr "Pobieranie NZB" #~ msgid "KB/s" #~ msgstr "KB/s" #~ msgid "Queued" #~ msgstr "W kolejce" #~ msgid "Add new downloads" #~ msgstr "Dodaj nowe pliki" #~ msgid "WARNINGS" #~ msgstr "OSTRZEŻENIA" #~ msgid " " #~ msgstr " " #~ msgid " or Report ID" #~ msgstr " lub ID raportu" #~ msgid "Hide files" #~ msgstr "Ukryj pliki" #~ msgid "Show files" #~ msgstr "Pokaż pliki" #~ msgid "Remain/Total" #~ msgstr "Pozostało/Razem" #~ msgid "History Size" #~ msgstr "Rozmiar historii" #~ msgid "Thread" #~ msgstr "Wątek" #~ msgid "Email Test Result" #~ msgstr "Wynik testu email" #~ msgid "General configuration" #~ msgstr "Ogólna konfiguracja" #~ msgid "Queue auto refresh interval:" #~ msgstr "Interwał automatycznego odświeżania kolejki" #~ msgid "Disable API-key" #~ msgstr "Wyłącz klucz API" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Katalog skryptów przetwarzania końcowego" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "Katalog zawierający skrypty przetwarzania końcowego" #~ msgid "Enable Filejoin" #~ msgstr "Włącz łączenie plików" #~ msgid "Enable built-in unrar functionality." #~ msgstr "Włącz wbudowaną funkcjonalność unrar" #~ msgid "Switches configuration" #~ msgstr "Konfiguracja przełączników" #~ msgid "Enable Quick Check" #~ msgstr "Włącz szybkie sprawdzanie" #~ msgid "Enable TS Joining" #~ msgstr "Włącz łączenie TS" #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Przerywaj po błędach CRC yEnc" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "Próbuj pobierać artykuły z błędami CRC z innych serwerów" #~ msgid "Step Four" #~ msgstr "Krok czwarty" #~ msgid "Step Five" #~ msgstr "Krok piąty" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "Np. 119 lub 563 dla SSL" #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Nieprawidłowe pliki par2, nie można zweryfikować lub naprawić" #~ msgid "Folder configuration" #~ msgstr "Konfiguracja katalogów" #~ msgid "QR Code" #~ msgstr "Kod QR" #~ msgid "Check result of unpacking" #~ msgstr "Sprawdzaj wyniki rozpakowywania" #~ msgid "Default Priority" #~ msgstr "Domyślny priorytet" #~ msgid "Enable MultiCore Par2" #~ msgstr "Włącz wielordzeniowy Par2" #~ msgid "Default Post-Processing" #~ msgstr "Domyślne przetwarzanie końcowe" #~ msgid "Default User Script" #~ msgstr "Domyślny skrypt użytkownika" #~ msgid "Other Switches" #~ msgstr "Inne przełączniki" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Zastąp niedopuszczalne znaki w nazwach katalogów" #~ msgid "Do not download" #~ msgstr "Nie pobieraj" #~ msgid "SSL type" #~ msgstr "Typ SSL" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Pokazuj czas w notacji AM/PM (nie dotyczy harmonogramu)" #~ msgid "Server configuration" #~ msgstr "Konfiguracja serwera" #~ msgid "Server definition" #~ msgstr "Definicja serwera" #~ msgid "Backup server" #~ msgstr "Serwer zapasowy" #~ msgid "Scheduling configuration" #~ msgstr "Konfiguracja harmonogramów" #~ msgid "Remove" #~ msgstr "Usuń" #~ msgid "Add Feed" #~ msgstr "Dodaj kanał" #~ msgid "Skip" #~ msgstr "Pomiń" #~ msgid "RSS Configuration" #~ msgstr "Konfiguracja RSS" #~ msgid "Delete Feed" #~ msgstr "Usuń kanał" #~ msgid "New Feed URL" #~ msgstr "Nowy URL kanału" #~ msgid "Feeds" #~ msgstr "Kanały" #~ msgid "Filters" #~ msgstr "Filtry" #~ msgid "Settings" #~ msgstr "Ustawienia" #~ msgid "Email Options" #~ msgstr "Opcje email" #~ msgid "Email Account Settings" #~ msgstr "Ustawienia konta email" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Włącz sortowanie i zmianę nazw odcinków" #~ msgid "Sorting configuration" #~ msgstr "Konfiguracja sortowania" #~ msgid "Groups / Indexer tags" #~ msgstr "Grupy / Etykiety indeksera" #~ msgid "Generic Sorting" #~ msgstr "Sortowanie standardowe" #~ msgid "folder" #~ msgstr "katalog" #~ msgid "Original Foldername" #~ msgstr "Oryginalna nazwa katalogu" #~ msgid "Are you sure you want to delete" #~ msgstr "Czy na pewno usunąć?" #~ msgid "Page" #~ msgstr "Strona" #~ msgid "Close" #~ msgstr "Zamknij" #~ msgid "Pause for 12 hours" #~ msgstr "Wstrzymaj na 12 godzin" #~ msgid "Pause for 24 hours" #~ msgstr "Wstrzymaj na 24 godziny" #~ msgid "Left" #~ msgstr "Pozostało" #~ msgid "Storage" #~ msgstr "Miejsce" #~ msgid "Plush Options" #~ msgstr "Opcje Plush" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Wczytaj: .nzb .rar .zip .gz" #~ msgid "Access" #~ msgstr "Dostęp" #~ msgid "Misc" #~ msgstr "Pozostałe" #~ msgid "Please enter a whole number." #~ msgstr "Wprowadź liczbę całkowitą" #~ msgid "Step One" #~ msgstr "Krok pierwszy" #~ msgid "Step Two" #~ msgstr "Krok drugi" #~ msgid "Step Three" #~ msgstr "Krok trzeci" #~ msgid "User-defined categories" #~ msgstr "Kategorie użytkownika" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "UWAGA: Zadanie \"%s\" zostało wstrzymane z powodu zaszyfrowanego pliku RAR" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "UWAGA: Zadanie \"%s\" zostało przerwane z powodu zaszyfrowanego pliku RAR" #~ msgid "Error: No secondary interface defined." #~ msgstr "Błąd: Nie zdefiniowano zapasowego interfejsu." #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "Nie znaleziono programu PAR2, naprawa nie będzie możliwa
" #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "Zadanie \"%s\" zostało ponownie dodane do kolejki" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "Zadania oznaczone przez '*' nie zostaną automatycznie pobrane." #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Nie można podłączyć gałęzi rejestru HKEY_CURRENT_USER." #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Nie udało się odczytać kluczy rejestru dla katalogów specjalnych" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "Brak modułu pyopenssl, należy go zainstalować w celu użycia HTTPS" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Brak oczekiwanego pliku: %s => błąd rozpakowywania archiwum RAR?" #~ msgid "Main packet not found..." #~ msgstr "Główny pakiet nieznaleziony..." #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Błąd importu modułu OpenSSL. Łączenie bez SSL" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd jest niekompatybilny z niektórymi programowymi firewallami.
\n" #~ " %s
\n" #~ " Przepraszamy, ale nie możemy obecnie rozwiązać tego problemu.
\n" #~ " Zgłoś problem u dostawcy swojego programu.
\n" #~ "
\n" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd wymaga wolnego portu TCP/IP dla wewnętrznego serwera WWW.
\n" #~ " Próbowano portu %s na %s, lecz użytkownik SABnzbd nie ma uprawnień do " #~ "jego użycia.
\n" #~ " W systemach OS X oraz Linux normalny użytkownik musi używać portów " #~ "powyżej 1023.
\n" #~ "
\n" #~ " Uruchom ponownie SABnzbd używając innego numeru portu." #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Wygląda na to, że używasz ZoneAlarm w systemie Vista.
" #~ msgid "You have no permisson to use port %s" #~ msgstr "Nie masz uprawnień do używania portu %s" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Nie udało się usunąć nzo z kolejki przetwarzania końcowego (id)" #~ msgid "View script output" #~ msgstr "Zobacz wynik działania skryptu" #~ msgid "Complete Dir" #~ msgstr "Katalog zakończonych" #~ msgid "Download speed" #~ msgstr "Prędkość pobierania" #~ msgid "Sort by name" #~ msgstr "Sortuj według nazwy" #~ msgid "Sort by age" #~ msgstr "Sortuj według wieku" #~ msgid "Sort by size" #~ msgstr "Sortuj według rozmiaru" #~ msgid "Purge Failed History" #~ msgstr "Usuń nieudane z historii" #~ msgid "Delete all failed items from History?" #~ msgstr "Usunąć z historii wszystkie nieudane pliki?" #~ msgid "Show Weblogging" #~ msgstr "Pokaż logi WWW" #~ msgid "OZnzb" #~ msgstr "OZnzb" #~ msgid "Secondary Web Interface" #~ msgstr "Zapasowy interfejs WWW" #~ msgid "Activate an alternative skin." #~ msgstr "Włącz alternatywną skórkę" #~ msgid "Web server authentication" #~ msgstr "Uwierzytelnienie serwera WWW" #~ msgid "HTTPS Support" #~ msgstr "Obsługa HTTPS" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "" #~ "Interwał automatycznego odświeżania strony kolejki w interfejsie WWW " #~ "(sekundy, 0=brak)" #~ msgid "Do not require the API key." #~ msgstr "Klucz API nie będzie wymagany" #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "UŻYWAJ NA WŁASNĄ ODPOWIEDZIALNOŚĆ!" #~ msgid "Processing Switches" #~ msgstr "Przełączniki przetwarzania" #~ msgid "Enable Unrar" #~ msgstr "Włącz unrar" #~ msgid "Enable built-in unzip functionality." #~ msgstr "Włącz wbudowaną funkcjonalność unzip" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "Łącz pliki kończące się na .001, .002 itd. w jeden plik" #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "Łącz pliki kończące się na .001.ts, 002.ts itd. w jeden plik" #~ msgid "Enable Par Cleanup" #~ msgstr "Włącz czyszczenie par2" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Czyść pliki par2 (jeśli weryfikacja/naprawa się powiedzie)" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "" #~ "Używane, kiedy przetwarzanie końcowe nie zostało określone przez kategorię" #~ msgid "Used when no user script is defined by the category." #~ msgstr "" #~ "Używany, kiedy skrypt użytkownika nie został określony przez kategorię" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Używany, kiedy priorytet nie został określony przez kategorię" #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Zastąp niedopuszczalne znaki w nazwach katalogów ich odpowiednikami (lub " #~ "usuń, jeśli odpowiednik nie jest dostępny)" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Użyj typu V23, chyba że dostawca wymaga innego!" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Użyj dwunastogodzinnego zegara (AM/PM)" #~ msgid "Only for optional servers" #~ msgstr "Tylko dla serwerów zapasowych" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Zastosuj maksymalną ilość prób tylko dla serwerów zapasowych" #~ msgid "Enable OZnzb Integration" #~ msgstr "Włącz integrację z OZnzb" #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Połączenie z indekserem OZnzb daje więcej możliwości, takich jak oceny i " #~ "dodatkowe informacje o stanie" #~ msgid "Site API Key" #~ msgstr "Klucz API strony" #~ msgid "Refer to https://www.oznzb.com/profile" #~ msgstr "Patrz: https://www.oznzb.com/profile" #~ msgid "Automatic Feedback" #~ msgstr "Automatyczne wysyłanie informacji zwrotnych" #~ msgid "Click below to test." #~ msgstr "Kliknij przycisk poniżej, aby przetestować" #~ msgid "Notification classes" #~ msgstr "Klasy powiadomień" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "Zgłaszaj wybrane klasy powiadomień (żadna, jedna lub wiele)" #~ msgid "Defines post-processing and storage." #~ msgstr "Definiuje przetwarzanie końcowe i przechowywanie" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Włącz standardowe sortowanie i zmianę nazw plików" #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Włącz, jeśli zadania nie są umieszczane we własnych katalogach" #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Włącz sortowanie i zmianę nazwy według daty" #~ msgid "Set Pause Interval" #~ msgstr "Ustaw czas wstrzymania" #~ msgid "Pause Interval" #~ msgstr "Czas wstrzymania" #~ msgid "Open Source URL" #~ msgstr "Otwórz źródłowy URL" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Pobierz kanał pobierze aktualną zawartość kanału. " #~ "Wymuś pobranie natychmiast pobierze wszystkie pasujące " #~ "pliki NZB." #~ msgid "Hour:Min" #~ msgstr "Godzina:Minuta" #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "" #~ "Chcę, aby dostęp do SABnzbd był możliwy z dowolnego komputera w mojej sieci" #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Chcę, aby dostęp do SABnzbd był możliwy tylko z mojego komputera" #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Zabezpiecz dostęp do SABnzbd hasłem (zalecane)" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Włącz dostęp do SABnzbd przez HTTPS" #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "Uruchom stronę SABnzbd w przeglądarce podczas uruchamiania programu" #~ msgid "This field is required." #~ msgstr "To pole jest wymagane" #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "Po zakończeniu ponownego uruchamiania dostęp będzie możliwy pod adresem: %s" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Pomiń sprawdzanie par2 dla plików prawidłowych w 100%" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Sprawdzaj wyniki rozpakowywania (należy wyłączyć dla niektórych systemów " #~ "plików)" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Ten klucz umożliwia indekserowi identyfikację klienta. Patrz: " #~ "https://www.oznzb.com/profile" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "Wyślij automatycznie wyliczone wyniki walidacji plików do indeksera" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "" #~ "Nie znaleziono programu unrar, rozpakowywanie plików RAR nie będzie " #~ "możliwe
" SABnzbd-2.3.2/po/main/pt_BR.po0000644000000000000000000044617313217005051014050 0ustar 00000000000000# Brazilian Portuguese translation for sabnzbd # Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2012. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2016-01-01 22:58+0000\n" "Last-Translator: lrrosa \n" "Language-Team: Brazilian Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:31+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Falha ao iniciar a interface web" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "" "Não foi possível encontrar o template web: %s. Tentando o template padrão" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "módulo _yenc... NÃO encontrado!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "aplicativo par2... NÃO encontrado!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" "Sua versão UNRAR é %s, nós recomendamos a versão %s ou superior.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "aplicativo unrar... NÃO encontrado!" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "aplicativo unzip... NÃO encontrado!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "aplicativo 7za... NÃO encontrado!" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Esteja ciente de que o nome de host 0.0.0.0 vai precisar de um endereço IPv6 " "para acesso externo" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "Portas HTTP e HTTPS não podem ser iguais" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "HTTPS desabilitado pela falta de arquivos CERT e KEY" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Falha ao iniciar a interface web " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "Não foi possível localizar o serviço SABHelper" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s iniciado" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Alerta" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Erro" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "Encerramento do SABnzbd concluído" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "O nome do host não foi definido." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "Não há conexões definidas. Por favor, defina pelo menos uma conexão." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Senha mascarada em ******, digite novamente" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Detalhes inválidos do servidor" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "" "Tempo esgotado: Tente habilitar o SSL ou conectar em uma porta diferente." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Tempo esgotado" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Endereço do servidor inválido." #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Servidor parou durante a sequência de login." #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Servidor requer usuário e senha." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Conexão com Sucesso!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Falha de autenticação, verifique usuário / senha." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "Excesso de conexões, por favor pause o download ou tente novamente mais tarde" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Não foi possível determinar o resultado da conexão (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Sinal %s encontrado. Salvando e saindo..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Erro fatal ao salvar estado" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Tentando obter NZB de %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Falha ao salvar %s" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Não é possível criar um arquivo temporário para %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Tentando definir o status do servidor inexistente %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Falha em tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Falha ao carregar %s" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Carga de %s falhou com os seguintes erros: %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Notificação de teste" #: sabnzbd/api.py msgid " Resolving address" msgstr " Resolvendo endereço" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Nenhum" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Padrão" #: sabnzbd/api.py msgid "unknown" msgstr "desconhecido" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Falha ao compilar a expressão para o termo pesquisado: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "Muito pouco espaço em disco. Forçando PAUSE" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Disco cheio! Forçando Pausa" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Erro de disco na criação do arquivo %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Erro fatal no Assembler" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Cancelado, criptografia detectada" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "ATENÇÃO: Extensão indesejada no arquivo RAR em \"%s\". O arquivo não " "desejado é %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "A extensão indesejada está no arquivo rar %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Cancelado, extensão indesejada detectada" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "ATENÇÃO: Tarefa \"%s\" em pausa em razão de pontuação (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "ATENÇÃO: Tarefa \"%s\" interrompida em razão de pontuação (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Interrompido, filtro de pontuação encontrado (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "faltando %s" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "vídeo" #: sabnzbd/assembler.py msgid "audio" msgstr "áudio" #: sabnzbd/assembler.py msgid "spam" msgstr "spam" #: sabnzbd/assembler.py msgid "passworded" msgstr "protegido por senha" #: sabnzbd/assembler.py msgid "downvoted" msgstr "votos negativos recebido" #: sabnzbd/assembler.py msgid "keywords" msgstr "palavras chave" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Quota esgotada, pausando o download" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s não é um endereço de e-mail válido" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Endereço do servidor necessário" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Não foi possível criar %s pasta %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Não é possível gravar no arquivo INI %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Não é possível criar um arquivo de backup para %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Senha %s codificada incorretamente" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s não é um valor octal correto" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "O caminho UNC \"%s\" não é permitido aqui" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Erro: Tamanho do caminho deve ser menor que %s." #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Erro: A fila não está vazia. Não será possível mudar de pasta." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "" "Não é possível gravar os dados de histórico, verifique as permissões de " "acesso!" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "Dados de histórico danificados, criado um substituto vazio" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "O comando SQL falhou. Consulte o log" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Falha ao fechar o banco de dados. Consulte o log" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Registro inválido de etapa no histórico para %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Falha ao decodificar %s" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Artigo yEnc mal formado em %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Erro desconhecido ao decodificar %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => faltando em todos os servidores. Descartando" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Concluído" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "Descompactados %s arquivos/pastas em %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "Não é possível ler %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Erro ao adicionar %s. Removendo" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Erro ao remover %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Não é possível ler a Pasta de Assistidos %s" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Continuar" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Pausado" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Você deve definir a largura de banda máxima antes de definir um limite de " "banda" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "O servidor %s será ignorado por %s minutos" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Falha ao iniciar %s@%s devido as seguintes razões: %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "Excesso de conexões ao servidor %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Provável compartilhamento de conta" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Falha de logon ao servidor %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Não é possível conectar ao servidor %s [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "A conexão a %s@%s falhou. Mensagem=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Servidor %s requer usuário/senha" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Erro suspeito no downloader" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Encerrando" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Falha ao conectar ao servidor de e-mail" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "Falha ao iniciar a conexão TLS" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "O servidor não respondeu propriamente a chamada de reconhecimento" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Falha ao autenticar com o servidor de e-mail" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Nenhum método de autenticação apropriado foi encontrado" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "Falha de autenticação desconhecida no servidor de e-mail" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Falha ao enviar o e-mail" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Falha ao fechar a conexão de e-mail" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "E-mail enviado com sucesso" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Não foi possível enviar, faltam dados obrigatórios" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Não é possível encontrar modelos de e-mail em %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Nenhum destinário fornecido, e-mail não enviado" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Codificação inválida do modelo de e-mail %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Nenhum modelo de e-mail encontrado" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "Para: %s\n" "De: %s\n" "Data: %s\n" "Assunto: SABnzbd informa Disco Cheio\n" "\n" "Olá,\n" "\n" "SABnzbd parou de baixar porque o disco está quase cheio.\n" "Por favor, arrume espaço e continue SABnzbd manualmente.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "Atenção: LOCALHOST é ambíguo, use endereço IP numérico." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Endereço de servidor \"%s:%s\" não é válido." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Faltando chave de sessão" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Erro: chave de sessão obrigatória" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Erro: chave de sessão incorreta" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "Chave de API faltando. Por favor insira a chave de API de Configuração-" ">Geral em seu programa de terceiros:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "Chave de API incorreta. Use a chave de API de Configuração->Geral em seu " "programa de terceiros:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Autenticação faltando. Por favor insira usuário/senha de Configuração->Geral " "em seu programa de terceiros:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Teste a nossa nova skin Glitter! Novo design otimizado para desktop e " "aparelhos móveis. Vá em Configurações -> Geral para mudar a sua skin" #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
Encerramento do SABnzbd concluído.
Espere cerca de 5 " "segundos e, em seguida, clique no botão abaixo.

Atualizar
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Feed" #: sabnzbd/interface.py msgid "Daily" msgstr "Diariamente" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "segunda-feira" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "terça-feira" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "quarta-feira" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "quinta-feira" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "sexta-feira" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "sábado" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "domingo" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "desligado" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Servidor não definido!" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Parâmetro incorreto" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Voltar" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "ERRO:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Valor incorreto para %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "d" #: sabnzbd/misc.py msgid "h" msgstr "h" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Não é possível criar a pasta %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "pasta %s: %s erro de acesso" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Falha ao criar (%s)" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Falha ao mover %s para %s" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Erro ao criar chave SSL e certificado" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Não é possível alterar permissões de %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Executando script" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "O pós-processamento foi cancelado (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Script" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Aninhamento de descompactação com muitos níveis [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Unindo" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Sequência de arquivos multiparte incompleta" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "A união de arquivos de %s falhou" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Erro \"%s\" na união de arquivos" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Erro \"%s\" ao executar file_join em %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] Unidos %s arquivos" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "A descompactação falhou. %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Erro \"%s\" ao descompactar os arquivos RAR" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Erro \"%s\" ao executar rar_unpack em %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "A exclusão de %s falhou!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Tentando descompactar com a senha \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "A descompactação falhou. O arquivo exige uma senha" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Descompactando" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Descompactar" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "A descompactação falhou. Não foi possível encontrar %s" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "ERRO: Não foi possível encontrar \"%s\"" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "A descompactação falhou. Erro de CRC" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "ERRO: CRC falhou em \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "A descompactação falhou. Erro de escrita ou disco cheio?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "ERRO: erro de escrita (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Descompactação falhou, o caminho é muito extenso" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "ERRO: caminho muito extenso (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "A descompactação falhou. Veja o log" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "ERRO: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Arquivo RAR inutilizável" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s arquivos em %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Erro \"%s\" ao executar unzip() em %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Testando 7zip com a senha \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "O arquivo 7ZIP \"%s\" está incompleto, impossível descompactar" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Não foi possível descompactar %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Verificação Rápida" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Reparar" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Verificação Rápida OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Iniciando reparação" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "Validação de par falhou em %s, enquanto QuickCheck foi completo!" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Reparação falhou, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Erro %s ao executar par2_repair no conjunto %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Erro \"%s\" ao executar par2_repair no conjunto %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] PAR2 recebeu opções incorretas. Verifique em Configuração->Opções" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Verificado em %s. Todos os arquivos corretos" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Verificado em %s. É necessário reparar" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "Obtendo %s blocos..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Obtendo" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "Reparação falhou. Blocos de reparação insuficientes (faltam %s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Reparando" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Reparado em %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Disco cheio" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Verificando" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Verificando" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Este servidor não permite SSL nesta porta" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Inicialização/Encerramento" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "NZB Adicionado" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Pós-processamento iniciado" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Tarefa concluída" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Tarefa com falha" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Fila concluída" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Outras Mensagens" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Não disponível" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Falha ao enviar mensagem Prowl" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Resposta incorreta do Pushover (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Falha ao enviar mensagem pushover" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Resposta incorreta do Pushbullet (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Falha ao enviar mensagem pushbullet" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "" "Fila antiga detectada, use \"Situação -> Reparação da fila\" para converter " "a fila" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Encontrado arquivo de fila incompatível. Não é possível continuar" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Erro ao carregar %s. Arquivo corrompido detectado" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "Falha ao renicializar NZB após a pre verificação (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB adicionado à fila" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Codificação desconhecida" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Arquivo %s está vazio. Pulando" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Falha ao importar %s arquivos de %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Arquivo NZB incompleto %s" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Arquivo NZB %s inválido. Pulando (razão=%s, linha=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Arquivo NZB %s vazio" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Ignorando NZB duplicado \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Pausando NZB duplicado \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Cancelado, não é possível concluir" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "DUPLICADO" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "CRIPTOGRAFADO" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "MUITO GRANDE" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "INCOMPLETO" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "INDESEJADO" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "FILTRADO" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "Espere %s segundo(s)" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Baixado em %s a uma média de %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Idade" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s artigos estavam malformados" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s artigos estavam faltando" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s artigos tinham duplicatas não-correspondentes" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s artigos foram removidos" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Erro ao importar %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Alertas" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Inativo" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Configuração" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Fila" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Limpar Fila" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Histórico" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Limpar Histórico" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Limitar Velocidade" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Pausar" #: sabnzbd/osxmenu.py msgid "min." msgstr "min." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Continuar" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Varrer pasta de assistidos" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Ler todos os feeds RSS" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Pasta de Finalizados" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Pasta de Não-Finalizados" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Resolução de problemas" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Reiniciar" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Reinicie sem login" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Sair" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Fila dos primeiros 10 items" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Esvaziar" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Histórico dos últimos 10 items" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Nova versão disponível" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Ir para o assistente" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Parando..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Problema com" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd precisa de uma porta tcp/ip livre para seu servidor web " "interno.
\n" " A porta %s em %s foi tentada, mas não está disponível.
\n" " Algum outro software usa a porta ou o SABnzbd já está rodando.
\n" "
\n" " Por favor reinicie o SABnzbd com um número de porta diferente." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "" "Se você receber esta mensagem de erro outra vez, tente um número " "diferente.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd precisa de um endereço de host válido para seu servidor web " "interno.
\n" " Você especificou um endereço inválido.
\n" " Valores seguros são localhost e 0.0.0.0
\n" "
\n" " Por favor reinicie o SABnzbd com um endereço de host correto." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd detectou dados salvos de outra versão do SABnzbd
\n" " mas não pode reutilizar os dados do outro programa.

\n" " Você pode querer terminar sua fila antes com o outro programa.

\n" " Após isso inicie este programa com a opção \"--clean\".
\n" " Isto irá apagar a fila atual e histórico!
\n" " SABnzbd leu o arquivo \"%s\"." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd não pode encontrar seus arquivos da interface web em %s.
\n" " Por favor instale o programa novamente.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd detectou um erro fatal:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd detectou que o arquivo sqlite3.dll está faltando.

\n" " Alguns anti-vírus mal projetados removem este arquivo.
\n" " Por favor, verifique o seu anti-vírus, tente reinstalar o SABnzbd e " "reclame com o seu fornecedor de anti-vírus.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Aperte a tecla Windows+R e digite a linha (exemplo):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Abra uma janela de terminal e digite a linha (exemplo):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "O programa não iniciou!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Erro fatal" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "Não é possível iniciar o navegador. Provavelmente não foi encontrado" #: sabnzbd/panic.py msgid "Access denied" msgstr "Acesso negado" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Erro %s: Você precisa fornecer um nome de usuário e senha válidos." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "" "O download pode falhar. Somente %s de %s necessários estão disponíveis" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "O download falhou - Não está em seu(s) servidor(s)" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Sem pós-processamento por causa de falha na verificação" #: sabnzbd/postproc.py msgid "Moving" msgstr "Movendo" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "Enviados %s para a fila" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Erro ao renomear \"%s\" para \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Falha ao mover arquivos" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Executando script de usuário %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "%s executado" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Código de saída do script é %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Mais" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "O pós-processamento falhou para %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "veja o arquivo de log" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "O download falhou" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "A limpeza de %s falhou." #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Erro ao remover a pasta de trabalho (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Download concluído" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Não é possível criar a pasta final %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Pós-processamento" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Nenhum conjunto par2" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Tentando verificação SFV" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Alguns arquivos falharam na verificação de \"%s\"" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Verificado com sucesso. Usando arquivos SFV." #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "com senha" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "A remoção de %s falhou" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Falha ao hibernar o sistema" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Falha ao colocar o sistema em espera" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Erro ao desligar o sistema" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "Indexador id (%s) não foi encontrador para avaliar arquivos" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Endereço do servidor" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "Chave API" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Descrição de feed RSS incorreta \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Falha ao obter RSS de %s: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Não há autenticação válida para o feed %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "" "Erro do servidor (código do servidor %s); não foi possível obter %s de %s" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "Servidor %s usa um certificado HTTPS não confiável" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "O feed RSS %s estava vazio" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Feed incompatível" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Entrada RSS vazia encontrada (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Exibir interface" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Abrir pasta de finalizados" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Encerrar" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Restante" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Adicionar NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Agendamento %s incorreto em %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Ação desconhecida: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Agendamento para um servidor inexistente %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Download" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Unir arquivos" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Código fonte" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Servidores" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Falha" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Falhou" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "Aguardando" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Reparando..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Extraindo..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Movendo..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Executando script..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Obtendo blocos extras..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Verificação Rápida..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Verificando..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Baixando" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Frequência" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Ação" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Parâmetros" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Tarefa" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "desativar o servidor" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "ativar o servidor" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Limite de velocidade" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Pausar Todos" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Pausar o pós-processamento" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Continuar o pós-processamento" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Ler feeds RSS" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Remover tarefas com falha" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Remover trabalhos encerrados" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Pausa tarefas de baixa prioridade" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Pausa tarefas de prioridade normal" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Pausa tarefas de alta prioridade" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Continua tarefas de baixa prioridade" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Continua tarefas de prioridade normal" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Continua tarefas de alta prioridade" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Ativar gerenciamento de cota" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Desativar gerenciamento de cota" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Desligado" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Muito Baixa" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Moderada" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normal" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Alta" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Emergencial" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Baixa" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "MB" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "GB" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "hora" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "horas" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "min" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "min" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "seg" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "segundos" #: sabnzbd/skintext.py msgid "day" msgstr "dia" #: sabnzbd/skintext.py msgid "days" msgstr "dias" #: sabnzbd/skintext.py msgid "week" msgstr "semana" #: sabnzbd/skintext.py msgid "Month" msgstr "Mês" #: sabnzbd/skintext.py msgid "Year" msgstr "Ano" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Dia do mês" #: sabnzbd/skintext.py msgid "This week" msgstr "Esta semana" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Este mês" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "Hoje" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Total" #: sabnzbd/skintext.py msgid "on" msgstr "ligado" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parâmetros:" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Versão do Python" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Página inicial" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "ou" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Host" #: sabnzbd/skintext.py msgid "Comment" msgstr "Comentário" #: sabnzbd/skintext.py msgid "Send" msgstr "Enviar" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Cancelar" #: sabnzbd/skintext.py msgid "Other" msgstr "Outros" #: sabnzbd/skintext.py msgid "Report" msgstr "Informar" #: sabnzbd/skintext.py msgid "Video" msgstr "Vídeo" #: sabnzbd/skintext.py msgid "Audio" msgstr "Áudio" #: sabnzbd/skintext.py msgid "Not used" msgstr "Não utilizado" #: sabnzbd/skintext.py msgid "or less" msgstr "ou menos" #: sabnzbd/skintext.py msgid "Log in" msgstr "" #: sabnzbd/skintext.py msgid "Log out" msgstr "" #: sabnzbd/skintext.py msgid "Remember me" msgstr "" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "A ferramenta de download automático da usenet" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Gravar" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Você tem certeza?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Excluir todos os arquivos baixados?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Início" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Configuração" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Situação" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Ajuda" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Fórum" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Gerais" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Pastas" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Opções" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Agendamento" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Notificações" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "E-mail" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Categorias" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Ordenação" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Especial" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Busca" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Pasta de Download" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "EM PAUSA" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "%s artigos em cache (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Carga do sistema" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Nova versão %s disponível em" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Tem certeza de que quer encerrar o SABnzbd?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Adicionar" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Adicionar Arquivo" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Categoria" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Processamento" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Prioridade" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Reparar" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Descompactar" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Excluir" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "U" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "D" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Forçar" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Parar" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "Digite a URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "Ao terminar a fila" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Desligar o PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "PC em espera" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Hibernar o PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Encerrar o SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Limite de velocidade" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Pausa de" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Ordem" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Nome" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "Estimado" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "IDADE" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Apagar" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Repetir" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Ações" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Scripts" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Eliminar todos os itens da fila?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Limpar NZBs" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Limpar NZBs & Excluir Arquivos" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Atualizar todos os trabalhos com falha" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Remover NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Remover NZB & Excluir Arquivos" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "de" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Artigos faltando" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Quota restante" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "manual" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Redefinir Quota agora" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Eliminar do histórico todos os itens concluídos?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Ocultar detalhes" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Mostrar detalhes" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Mostrar Falhados" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Mostrar Todos" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Tamanho" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Limpar NZBs Falhados" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Limpar NZBs Falhados & Excluir Arquivos" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Limpar NZBs Terminados" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "NZB Suplementar Opcional" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Caminho" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Atualizar todos com falha" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Atualizar todos" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus/spam" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "Fora da retenção" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Outro problema" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Forçar Desconexão" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Isto irá enviar um e-mail de teste para sua conta." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Mostrar Logs" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Testar E-mail" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Logs" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Erros/Avisos" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ Info" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ Debug" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Conexões" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Últimos Alertas" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "limpar" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Desbloquear" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Identificador de artigo" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Conjunto de arquivos" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Quando" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Tipo" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Ativo" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Painel de controle" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Conexão falhou!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Enderaço IPv4 local" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Endereço IPv4 público" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "Endereço IPv6" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Nome do servidor / DNS Lookup" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "Modelo da CPU" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "Performance do Sistema (Pystone)" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Velocidade de download da pasta" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Completar velocidade da pasta" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Velocidade de escrita" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "" "Não foi possível escrever. Verifique se o diretória tem permissão de escrita." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Clique no botão de Repetir abaixo para determinar" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Repetir teste" #: sabnzbd/skintext.py msgid "Config File" msgstr "Arquivo de Configuração" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Cache utilizado" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Isto irá reiniciar o SABnzbd.
Use-o quando você achar que o programa " "tem um problema de estabilidade.
Os downloads serão pausados antes de " "reiniciar e retomados depois." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" #: sabnzbd/skintext.py msgid "Advanced" msgstr "" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Existem tarefas órfãs na pasta de downloads.
Você pode optar por excluí-" "las (incluindo arquivos) ou enviá-las de volta para a fila." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "O botão \"Reparar\" irá reiniciar o SABnzbd e fazer uma reconstrução
completa do conteúdo da fila, preservando arquivos já baixados.
Isto " "modificará a ordem da fila." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "As alterações não foram salvas e serão perdidas." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Habilitar Unzip" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "Ativar 7zip" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" #: sabnzbd/skintext.py msgid "Version" msgstr "Versão" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Tempo ativo" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Backup" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Leia a sessão ajuda no Wiki sobre isso!" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Reiniciando SABnzbd..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Mudanças exigirão um reinício do SABnzbd!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "Servidor Web do SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "Host do SABnzbd" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Computador onde o SABnzbd ficará ativo." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "Porta do SABnzbd" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Porta onde o SABnzbd será ativado." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Interface Web" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Escolha uma skin." #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "Usuário do SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Usuário de autenticação opcional." #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "Senha do SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Senha de autenticação opcional." #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "Habilitar HTTPS" #: sabnzbd/skintext.py msgid "not installed" msgstr "não instalado" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Ativar acesso à interface por um endereço HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "Porta HTTPS" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Se estiver vazio, a porta padrão só irá funcionar com HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "Certificado HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Nome do arquivo ou caminho para o certificado HTTPS." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "Chave HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Nome do arquivo ou caminho para a chave HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "Cadeia de Certificados HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Nome de arquivo ou caminho da Cadeia HTTPS." #: sabnzbd/skintext.py msgid "Tuning" msgstr "Ajustes finos" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "Intervalo de verificação de RSS" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Intervalo de verificação (em minutos, ao menos 15). Inativo quando você usar " "o Agendador!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Velocidade máxima da linha" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Percentual de velocidade da linha" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "" "Qual percentual de velocidade da linha o SABnzbd deve utilizar, por exemplo, " "50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Limite de Cache de Artigos" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Manter artigos em memória para reduzir o acesso a disco.
Em bytes, " "opcionalmente seguido de K,M,G. Por exemplo: \"64M\" ou \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Lista de Limpeza" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Lista de extensões de arquivo que devem ser excluídos após o download.
Por exemplo: nfo ou nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Salvar Alterações" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Reiniciar" #: sabnzbd/skintext.py msgid "Language" msgstr "Idioma" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Selecione um idioma para a interface web." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "Esta chave dará a programas de terceiros pleno acesso ao SABnzbd." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "Chave NZB" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "Esta chave permitirá que programas de terceiros adicionem NZBs ao SABnzbd." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Gerar Nova Chave" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "API Key QR Code" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Lista de intervalos de rede local" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Todas os endereços da rede local começam com esse prefixo (geralmente " "\"192.168.1.\")" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Acesso externo da Internet" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" #: sabnzbd/skintext.py msgid "No access" msgstr "Sem acesso" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Adicionar arquivos NZB " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (sem Configuração)" #: sabnzbd/skintext.py msgid "Full API" msgstr "API completa" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Interface Web completa" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "NOTA: Pastas serão criadas automaticamente ao salvar. Você pode " "usar caminhos absolutos para salvar fora das pastas padrão." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Usar Pastas" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Navegar" #: sabnzbd/skintext.py msgid "In" msgstr "Em" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Pasta Temporária de Downloads" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Local para armazenar downloads não processados.
Só pode ser alterado " "quando a fila estiver vazia." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Espaço livre mínimo para a pasta temporária de downloads" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Pausar automaticamente quando o espaço livre estiver abaixo deste valor.
Em bytes, opcionalmente seguido de K,M,G,T. Por exemplo: \"800M\" ou " "\"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Pasta de Downloads Concluídos" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Local para armazenar downloads concluídos, totalmente processados​​.
Pode ser anulado por categorias definidas pelo usuário." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Permissões para downloads concluídos" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Definir padrão de permissões para arquivos/pastas concluídos.
Em " "notação octal. Por exemplo: \"755\" ou \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Pasta de Assistidos" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Pasta para monitorar por arquivos .nzb.
Também procura arquivos .nzb " "em arquivos .zip, .rar e .tar.gz." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Velocidade de Varredura na Pasta de Assistidos" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Quantidade de segundos entre as varreduras de arquivos .nzb." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Pasta de Modelos de E-mail" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Pasta contendo modelos de e-mail definidos pelo usuário" #: sabnzbd/skintext.py msgid "Password file" msgstr "Arquivo de senhas" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Arquivo contendo todas as senhas que serão testadas em arquivos RAR " "criptografados." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Pastas de Sistema" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Pasta Administrativa" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Localização do banco de dados de histórico e administrador de fila.
Só pode ser alterado quando a fila estiver vazia." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "Dados não serão movidos. Será necessário reiniciar o SABnzbd!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Pasta de Log" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Local dos arquivos de log do SABnzbd.
Será necessário reiniciar o " "SABnzbd!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr "Pasta de Backup de .nzb" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Local onde os arquivos .nzb serão armazenados." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Pasta Inicial Padrão" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Baixar todos os arquivos PAR2" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Ativa descompactação recursiva" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Descompacta os arquivos (rar, zip, 7z) dentro de arquivos." #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Ignorar qualquer pasta arquivada" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Todos os arquivos irão em uma única pasta." #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Apenas Obter Artigos para o Topo da Fila" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Ative para menor uso de memória. Desative para impedir que trabalhos lentos " "bloqueiem a fila." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Pós-processar apenas os trabalhos verificados" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "" "Realizar pós-processamento apenas em trabalhos que passaram todas as " "verificações PAR2." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Ação quando RAR criptografado é baixado" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "Em caso de \"Pausa\", você precisa definir uma senha e retomar a tarefa." #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Detectar Downloads Duplicados" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Detecta episódios duplicados em séries" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Descartar" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Cancelar" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Ação quando extensão indesejada for detectada" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "Ação quando uma extensão indesejada é detectada em arquivos RAR" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Extensões indesejadas" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Lista todas as extensões indesejadas. Por exemplo: exe ou exe, " "com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Habilitar verificações baseadas em SFV" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Fazer uma verificação extra baseada em arquivos SFV." #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "O script do usuário pode marcar um trabalho como falho" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Quando um script do usuário retornar um código de saída diferente de zero, o " "trabalho será marcado como falho" #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "Em caso de falha, tente um NZB alternativo" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "" "Alguns servidores fornecem um NZB alternativo quando um download falha." #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Habilitar renomeação de pasta" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Usar nomes temporários durante o pós-processamento. Desative quando seu " "sistema não lidar com isso corretamente." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Script de usuário de pré-fila" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Utilizado antes de um NZB entrar na fila." #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Parâmetros Extras PAR2" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Parâmetros Nice" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "Parâmetros IONice" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Desconecte quando fila vazia" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "" "Desconecte do(s) servidor(es) Usenet quando a fila estiver vazia ou pausada." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Ordernar por Idade" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Classificar automaticamente os itens por (média de) idade." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Procurar por nova versão" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Checar semanalmente por nova versão do SABnzbd." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "Também versões de testes" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Substituir espaços no nome da pasta" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Substituir espaços por sublinhado no nome das pastas." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Substituir pontos no nome da pasta" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Substituir pontos por espaços no nome da pasta." #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Tornar Windows compatível" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "" "Para servidores: tenha certeza que os nomes são compatíveis com o Windows." #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Abrir navegador ao iniciar" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Abrir o navegador padrão ao iniciar o SABnzbd." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Pausar o download durante o pós-processamento." #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Pausar o download no início do pós-processamento e retomar quando concluído." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Ignorar amostras" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Exclui arquivos de amostra. Exemplo: amostras de vídeo." #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Excluir após download" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" #: sabnzbd/skintext.py msgid "Server" msgstr "Servidor" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Pós-processamento" #: sabnzbd/skintext.py msgid "Naming" msgstr "Nomeando" #: sabnzbd/skintext.py msgid "Quota" msgstr "Quota" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indexação" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Quanto pode ser baixado neste mês (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Primeiro dia do ciclo" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "Em que dia do mês ou da semana (1 = segunda-feira) seu provedor de Internet " "redefine sua quota? (Opcionalmente com hh: mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Retomar automaticamente" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "O download deve retomar quando a quota for restabelecida?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Período da quota" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "A quota é restabelecida a cada dia, semana ou mês?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Verifique antes de baixar" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Tentar prever a conclusão bem sucedida de um futuro download? (lento!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Máximo de tentativas" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Número máximo de tentativas por servidor." #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Cancela tarefas que não podem ser concluídas" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Quando durante o download ficar claro que muitos dados estão faltando, " "cancela a tarefa" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Habilitar filtros" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Ação faz o download de acordo com as regras de filtro" #: sabnzbd/skintext.py msgid "Abort If" msgstr "Interrompa se" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Ou então pause se" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Pontuação do vídeo" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Pontuação do áudio" #: sabnzbd/skintext.py msgid "Spam" msgstr "Spam" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Confirmado" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Mais votos negativos do que positivos" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Palavras chave do título" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Lista separada por vírgulas" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Balanceamento de carga do servidor" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Prevenir balanceamento de carga" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Permitir balanceamento de carga" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Permitir balanceamento de carga com optimização para IPv6" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "Útil se um newsserver tem mais de um endereço IPv4/IPv6" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Adicionar Servidor" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Descrição do servidor" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Porta" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Usuário" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Senha" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Tempo limite" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Tempo de retenção" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Desativado" #: sabnzbd/skintext.py msgid "Minimal" msgstr "" #: sabnzbd/skintext.py msgid "Strict" msgstr "" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 é a prioridade mais alta, 100 é a prioridade mais baixa" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Opcional" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Habilitar" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Remover servidor" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Testar Servidor" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Limpar Contadores" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Testando detalhes do servidor..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Largura de banda" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Enviar Grupo" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Enviar comando do grupo antes de solicitar artigos." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Apenas utilize esse servidor para essas categorias." #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Notas pessoais" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Adicionar Agendamento" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Agendamentos Atuais" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "A caixa de seleção ao lado do nome do feed deve ser assinalada para que o " "feed seja ativado e automaticamente verificado por novos itens.
Quando " "um feed é adicionado, ele só vai pegar novos itens e não algo que já esteja " "no feed RSS a menos que você pressione \"Forçar Download\"." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Ler Feed" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Forçar Download" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Filtro" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Aceitar" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Recusar" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Requer" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "RequiresCat" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "No mínimo" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "No máximo" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "De SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Correspondido" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Não Encontrado" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Baixados" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Ler Todos os Feeds Agora" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "Notificar por e-mail na conclusão da tarefa" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Nunca" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Sempre" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Somente para erros" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Notificações de Disco Cheio" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "" "Enviar e-mail quando o disco estiver cheio e SABnzbd estiver pausado." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Enviar notificações RSS" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "Enviar e-mail quando um feed RSS adicionar tarefas à fila." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "Servidor SMTP" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Define o servidor para envio de e-mails." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "Destinatário do E-mail" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "Endereço de e-mail para receber os e-mails." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "E-mail do Remetente" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Quem devemos dizer que enviou o e-mail?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "Nome de usuário OPCIONAL da conta" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Nome da conta, para e-mails com autenticação." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "Senha OPCIONAL da conta" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Senha, para e-mails com autenticação." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Habilitar Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Enviar notificações ao Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Utilize apenas para servidor remoto Growl (host: porta)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Senha do servidor" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Senha opcional para o servidor Growl" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "Habilitar NotifyOSD" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Enviar as notificações a NotifyOSD." #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Centro de Notificações" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Envia notificações para o Centro de Notificações" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Habilitar notificações Windows" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Notificações Windows" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Ativar notificações Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Requer uma conta Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "Chave API para Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Chave API pessoal para Prowl (obrigatório)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Habilitar notificações Pushover" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Necessário uma conta Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Token da aplicação" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Token da aplicação (obrigatório)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Chave do usuário" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Chave do usuário (obrigatório)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Dispositivo(s)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Dispositivo(s) para qual a mensagem deve ser enviada" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Habilitar notificações Pushbullet" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Necessária uma conta Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Chave API pessoal" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Chave Pushbullet API pessoal (necessária)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Dispositivo" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Dispositivo para qual a mensagem deve ser enviada" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Para evitar a criação de pastas de trabalho, adicione um asterisco (*) " "depois do caminho." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Caminho base das pastas relativas" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Pasta/Caminho" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Ordenação de Séries" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Ativar a ordenação de TV" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Modelo do padrão" #: sabnzbd/skintext.py msgid "Clear" msgstr "Limpar" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "" #: sabnzbd/skintext.py msgid "Presets" msgstr "Predefinições" #: sabnzbd/skintext.py msgid "Example" msgstr "Exemplo" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Ativar a ordenação de filmes" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Manter em pastas separadas os downloads soltos" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Categorias Afetadas" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Significado" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Modelo" #: sabnzbd/skintext.py msgid "Result" msgstr "Resultado" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Pasta Da Temporada" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Pasta Da Temporada" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Pasta Do Episódio" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Pasta Do Episódio" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Tí­tulo" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Nome Filme" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Nome.Filme" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Nome_Filme" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Nome do Show" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Nome.do.Show" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Nome_do_Show" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Número da Temporada" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Número do Episódio" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Nome do Episódio" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Nome.Episódio" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Nome_Episódio" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Extensão do arquivo" #: sabnzbd/skintext.py msgid "Extension" msgstr "Extensão" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Número do Episódio" #: sabnzbd/skintext.py msgid "Decade" msgstr "Década" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Nome do arquivo original" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Minúsculas" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEXTO" #: sabnzbd/skintext.py msgid "text" msgstr "texto" #: sabnzbd/skintext.py msgid "file" msgstr "arquivo" #: sabnzbd/skintext.py msgid "Sort String" msgstr "String de ordenação" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Rótulo multi-parte" #: sabnzbd/skintext.py msgid "In folders" msgstr "Em pastas" #: sabnzbd/skintext.py msgid "No folders" msgstr "Sem pastas" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Ordenação por data" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Ativar a ordenação por data" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Pasta do Nome do Show" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "Pastas Ano-Mês" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Pastas Diárias" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "ajuste de maiúsculas" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Resultado Processado" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Opções raramente utilizadas. Para seu significado e explicação, clique no " "botão Ajuda para ir para a página Wiki.
Não altere estas sem checar o " "Wiki em primeiro lugar, já que algumas têm sérios efeitos colaterais.
Os " "valores padrão estão entre parênteses." #: sabnzbd/skintext.py msgid "Values" msgstr "Valores" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Editar Detalhes do NZB" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Eliminar" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Topo" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Para cima" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Para baixo" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Base" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Todos" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Inverter" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Nome do arquivo" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Assunto" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Seleção" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Pausar por 5 minutos" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Pausar por 15 minutos" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Pausar por 30 minutos" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Pausar por 1 hora" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Pausar por 3 horas" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Pausar por 6 horas" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "restantes" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Espaço Disponível" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Pasta temporária" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Multi-Operações" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Segure a tecla shift para selecionar um intervalo" #: sabnzbd/skintext.py msgid "Check all" msgstr "Selecionar todos" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Reiniciar SABnzbd" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Estado e opções de interface" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Ou arraste e solte arquivos na janela!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Conexão perdida com SABnzbd.." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "" "No caso de reinício do SABnzbd, esta janela irá desaparecer automaticamente!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "AVISO:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Obter" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Taxa de atualização" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Usar configurações globais de interface" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Limite de itens na fila" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Limite de itens no histórico" #: sabnzbd/skintext.py msgid "Date format" msgstr "Formato da data" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Coluna extra da fila" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "página" #: sabnzbd/skintext.py msgid "Loading" msgstr "Carregando" #: sabnzbd/skintext.py msgid "articles" msgstr "artigos" #: sabnzbd/skintext.py msgid "Rename" msgstr "Renomear" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Reparação da fila" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Exibir conexões ativas" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Trabalhos órfãos" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Enviar de volta para a fila" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Excluir Todos" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Repetir todos" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Buscar NZB de uma URL" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "Enviar NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Opcionalmente, especifique um nome de arquivo" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Formatos: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Enviar" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Abrir URL Informativa" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Enviado. Obrigado!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Nada selecionado!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Remover todos os arquivos selecionados" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Esconder/Exibir arquivos completos" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Exibir Log do Script" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Atualização Disponível!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Personalizado" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Velocidade" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Confirmar Exclusões da Fila" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Confirmar Exclusões do Histórico" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Por quanto tempo ou até quando você quer pausar? (em Inglês!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Perdão, não conseguimos interpretar isso. Tente novamente." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Pausar por..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Atualizar" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Ordenar por Idade Mais antigo→Mais novo" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Ordenar por Idade Mais novo→Mais antigo" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Ordenar por Nome A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Ordenar por Nome Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Ordenar por Tamanho Menor→Maior" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Ordenar por Tamanho Maior→Menor" #: sabnzbd/skintext.py msgid "Uploading" msgstr "" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "" #: sabnzbd/skintext.py msgid "Removing job" msgstr "" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Ant" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Próx" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Limpar o Histórico?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Você deve habilitar o JavaScript para Plush funcionar!" #: sabnzbd/skintext.py msgid "Options" msgstr "Opções" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Pausar por quantos minutos?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Menu Superior" #: sabnzbd/skintext.py msgid "On Finish" msgstr "Ao Concluir" #: sabnzbd/skintext.py msgid "Sort" msgstr "Ordenar" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Ordenar por Idade (Mais antigo→Mais novo)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Ordenar por Idade (Mais novo→Mais antigo)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Ordenar por Nome (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Ordenar por Nome (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Ordenar por Tamanho (Menor→Maior)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Ordenar por Tamanho (Maior→Menor)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Limpar a fila?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Repetir todos os trabalhos com falha no Histórico?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Eliminar" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Velocidade Máx" #: sabnzbd/skintext.py msgid "Range" msgstr "Intervalo" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Aplicar aos Selecionados" #: sabnzbd/skintext.py msgid "Everything" msgstr "Tudo" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Taxa de Atualização" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Largura do Contêiner" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "" "Isso irá impedir que o conteúdo seja atualizado quando o cursor do mouse " "estiver sobre a fila." #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Impedir Atualizações no Foco" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Enviar" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Enviar: .nzb .rar .zip .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Progresso" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Não há espaço em disco suficiente para completar os downloads!" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Disponível (Temporário)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "OCIOSO" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Downloads" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Exclusão Concluída" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Excluir do histórico todos os itens com falha?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Falha na Exclusão" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Repetir todos os trabalhos com falha?" #: sabnzbd/skintext.py msgid "Links" msgstr "Atalhos" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Mostrando %s a %s de %s resultados" #: sabnzbd/skintext.py msgid "No results" msgstr "Sem resultados" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Mostrando um resultado" #: sabnzbd/skintext.py msgid "First" msgstr "Primeira" #: sabnzbd/skintext.py msgid "Last" msgstr "Última" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "Email Enviado!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Notificação Enviada!" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Salvando..." #: sabnzbd/skintext.py msgid "Saved" msgstr "Salvo" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Alternar Adição de NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "DualView1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "DualView2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Tem certeza que deseja reiniciar o SABnzbd?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Ocultar Opções de Edição" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Mostrar Opções de Edição" #: sabnzbd/skintext.py msgid "Edit" msgstr "Editar" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Tempo restante" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "Assistente de Início Rápido do SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "Versão do SABnzbd" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Anterior" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Detalhes do Servidor" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Por favor insira os detalhes de seu provedor de usenet primário." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "O número de conexões permitidas por seu provedor" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "Ex: 8 ou 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Selecione somente se seu provedor permitir conexões SSL." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Clique para testar os detalhes informados." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Ex." #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "A configuração está completa!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd agora será executado em segundo plano." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "Fechar qualquer janela/aba do navegador NÃO vai fechar o SABnzbd." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Recomenda-se que você adicione este local como favorito para acessar o " "SABnzbd quando ele estiver sendo executado em segundo plano." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Mais ajuda pode ser encontrada em nosso" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Ir para o SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Sair do SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Iniciar o Assistente" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd não possui QUALQUER GARANTIA.\n" "É software livre, e você está convidado a redistribuí-lo sob certas " "condições.\n" "Está licenciado sob a LICENÇA PÚBLICA GERAL GNU Versão 2 ou (a seu critério) " "qualquer versão posterior.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "Para baixar a partir da usenet você precisa ter acesso a um provedor. Seu " "provedor de Internet pode fornecer-lhe acesso, no entanto, um provedor " "exclusivo é recomendado." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "Não tem um provedor usenet? Recomendamos testar %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Erro ao obter informações de TV (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Falha ao renomear: %s para %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Falha ao renomear arquivo similar: %s para %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Nome de servidor não encontrado" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Acesso não autorizado" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "URLGRABBER PAROU DE FUNCIONAR" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Arquivo NZB inutilizável" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "A busca da URL falhou; %s" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "ATENÇÃO: Tarefa \"%s\" em pausa por causa de arquivo RAR criptografado" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "Erro de CRC em %s (%s -> %s)" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "A pasta \"%s\" não existe" #~ msgid "SQL Commit Failed, see log" #~ msgstr "O commit do SQL falhou. Consulte o log" #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Sua versão do UNRAR não é recomendada. Pegue-a de " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgid "Error: No secondary interface defined." #~ msgstr "Erro: Nenhuma interface secundária definida." #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "" #~ "Nenhum programa UNRAR foi encontrado. Não será possível descompactar " #~ "arquivos RAR
" #~ msgid "Initiating restart...
" #~ msgstr "Fazendo o reinício...
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "" #~ "Nenhum programa PAR2 foi encontrado. Reparos não serão possíveis
" #~ msgid "Not matched" #~ msgstr "Não correspondido" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "As tarefas marcadas com um '*' não serão baixadas automaticamente." #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "A tarefa \"%s\" foi adicionada novamente à fila" #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Falha ao ler chaves de registro para pastas especiais" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Não é possível conectar à seção de registro HKEY_CURRENT_USER." #~ msgid "Downloaded so far" #~ msgstr "Baixados até agora" #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Não é possível abrir a chave de registro \"%s\"." #~ msgid "Try again" #~ msgstr "Tente novamente" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "Módulo pyOpenSSL ausente. Instale-o para obter acesso https" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Faltando arquivo esperado: %s => erro no unrar?" #~ msgid "Main packet not found..." #~ msgstr "Pacote principal não encontrado..." #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Arquivos PAR2 inválidos. Não é possível verificar ou reparar" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "A descompactação falhou. Este(s) arquivo(s) estão faltando:" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "A descompactação falhou. Um arquivo esperado não foi descompactado" #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Erro ao importar o módulo OpenSSL. Conectando-se sem SSL" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd precisa de uma porta tcp/ip livre para seu servidor web " #~ "interno.
\n" #~ " A porta %s em %s foi tentada, mas a conta usada para o SABnzbd não tem " #~ "permissão para usá-la.
\n" #~ " Nos sistemas OSX e Linux, usuários normais devem usar portas acima de " #~ "1023.
\n" #~ "
\n" #~ " Por favor reinicie o SABnzbd com um número de porta diferente." #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd não é compatível com alguns softwares de firewall.
\n" #~ " %s
\n" #~ " Lamentamos, mas não podemos resolver esta incompatibilidade no " #~ "momento.
\n" #~ " Por favor, registre uma reclamação com seu fornecedor de firewall.
\n" #~ "
\n" #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "É provável que você esteja usando o ZoneAlarm no Vista.
" #~ msgid "OK" #~ msgstr "OK" #~ msgid "You have no permisson to use port %s" #~ msgstr "Você não tem permissão para usar a porta %s" #~ msgid "View script output" #~ msgstr "Ver saída do script" #~ msgid "Get NZB" #~ msgstr "Obter NZB" #~ msgid "KB/s" #~ msgstr "KB/s" #~ msgid "Queued" #~ msgstr "Na fila" #~ msgid "WARNINGS" #~ msgstr "AVISOS" #~ msgid "Complete Dir" #~ msgstr "Pasta Completados" #~ msgid "Download speed" #~ msgstr "Velocidade de download" #~ msgid "Add new downloads" #~ msgstr "Adicionar novos downloads" #~ msgid " " #~ msgstr " " #~ msgid " or Report ID" #~ msgstr " ou Report ID" #~ msgid "Sort by name" #~ msgstr "Ordenar pelo nome" #~ msgid "Sort by age" #~ msgstr "Ordenar por idade" #~ msgid "Sort by size" #~ msgstr "Ordenar por tamanho" #~ msgid "Hide files" #~ msgstr "Ocultar arquivos" #~ msgid "Show files" #~ msgstr "Exibir arquivos" #~ msgid "Remain/Total" #~ msgstr "Restante/Total" #~ msgid "History Size" #~ msgstr "Tamanho do histórico" #~ msgid "Delete all failed items from History?" #~ msgstr "Eliminar do histórico todos os itens falhados?" #~ msgid "Purge Failed History" #~ msgstr "Limpar Histórico de Falhas" #~ msgid "Show Weblogging" #~ msgstr "Mostrar Logs da Web" #~ msgid "Thread" #~ msgstr "Tópico" #~ msgid "Email Test Result" #~ msgstr "Resultado do Teste de E-mail" #~ msgid "General configuration" #~ msgstr "Configuração geral" #~ msgid "Secondary Web Interface" #~ msgstr "Interface Web Secundária" #~ msgid "Web server authentication" #~ msgstr "Autenticação do servidor web" #~ msgid "Activate an alternative skin." #~ msgstr "Ativar uma skin alternativa." #~ msgid "HTTPS Support" #~ msgstr "Suporte HTTPS" #~ msgid "Queue auto refresh interval:" #~ msgstr "Intervalo de atualização da fila:" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "" #~ "Intervalo de atualização da página da interface web da fila (em segundos, 0 " #~ "= nenhum)." #~ msgid "Folder configuration" #~ msgstr "Configuração de pasta" #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "USE POR SUA CONTA E RISCO!" #~ msgid "Disable API-key" #~ msgstr "Desabilitar Chave API" #~ msgid "Do not require the API key." #~ msgstr "Não requer a chave API." #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "Pasta contendo scripts de usuário para pós-processamento" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Pasta de Arquivos de Pós-Processamento" #~ msgid "Switches configuration" #~ msgstr "Configuração de opções" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Pular verificação par2 quando os arquivos forem 100% válidos." #~ msgid "Processing Switches" #~ msgstr "Opções de Processamento" #~ msgid "Enable Quick Check" #~ msgstr "Habilitar Verificação Rápida" #~ msgid "Enable Filejoin" #~ msgstr "Habilitar Filejoin" #~ msgid "Enable TS Joining" #~ msgstr "Habilitar União TS" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "Unir arquivos terminando em .001, .002, etc. em um arquivo." #~ msgid "Enable Par Cleanup" #~ msgstr "Habilitar Limpeza de Par" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Limpar arquivos par (se a verificação/reparo for bem sucedida)." #~ msgid "Enable Unrar" #~ msgstr "Habilitar Unrar" #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "Unir arquivos terminando em .001.ts, .002.ts, etc. em um arquivo." #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Falhar em erros CRC yEnc" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "" #~ "Quando o artigo possuir um erro de CRC, tentar obtê-lo de outro servidor." #~ msgid "Default Post-Processing" #~ msgstr "Pós-processamento Padrão" #~ msgid "Check result of unpacking" #~ msgstr "Verificar o resultado da descompactação" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Verificar o resultado da descompactação (precisa ficar desativado em alguns " #~ "sistemas de arquivos)." #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "" #~ "Usado quando nenhum pós-processamento estiver definido pela categoria." #~ msgid "Used when no user script is defined by the category." #~ msgstr "Usado quando nenhum script de usuário é definido pela categoria." #~ msgid "QR Code" #~ msgstr "QR Code" #~ msgid "Default User Script" #~ msgstr "Script de usuário padrão" #~ msgid "Default Priority" #~ msgstr "Prioridade Padrão" #~ msgid "Enable MultiCore Par2" #~ msgstr "Habilitar MultiCore Par2" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Utilizado quando nenhuma prioridade é definida pela categoria." #~ msgid "Other Switches" #~ msgstr "Outras Opções" #~ msgid "Do not download" #~ msgstr "Não baixar" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Utilizar relógio com 12 horas (AM/PM)" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Exibir horas na notação AM/PM (não afeta o agendador)." #~ msgid "Only for optional servers" #~ msgstr "Apenas para servidores opcionais" #~ msgid "SSL type" #~ msgstr "Tipo SSL" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Aplicar o máximo de tentativas somente com servidores opcionais" #~ msgid "Server definition" #~ msgstr "Definições do servidor" #~ msgid "Server configuration" #~ msgstr "Configurações do servidor" #~ msgid "Backup server" #~ msgstr "Servidor backup" #~ msgid "Click below to test." #~ msgstr "Clique abaixo para testar." #~ msgid "Scheduling configuration" #~ msgstr "Configuração de agendamentos" #~ msgid "Add Feed" #~ msgstr "Adicionar Feed" #~ msgid "RSS Configuration" #~ msgstr "Configuração de RSS" #~ msgid "Remove" #~ msgstr "Remover" #~ msgid "Delete Feed" #~ msgstr "Remover Feed" #~ msgid "New Feed URL" #~ msgstr "Nova URL de Feed" #~ msgid "Feeds" #~ msgstr "Feeds" #~ msgid "Skip" #~ msgstr "Pular" #~ msgid "Filters" #~ msgstr "Filtros" #~ msgid "Settings" #~ msgstr "Configurações" #~ msgid "Email Options" #~ msgstr "Opções de e-mail" #~ msgid "Email Account Settings" #~ msgstr "Configurações da Conta de E-mail" #~ msgid "User-defined categories" #~ msgstr "Categorias do usuário" #~ msgid "Defines post-processing and storage." #~ msgstr "Define os métodos de pós-processamento e de armazenamento." #~ msgid "Sorting configuration" #~ msgstr "Configuração de classificação" #~ msgid "Groups / Indexer tags" #~ msgstr "Indexador Grupos/Etiquetas" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Ativar a ordenação e a renomeação genérica dos Filmes" #~ msgid "Generic Sorting" #~ msgstr "Ordenação genérica" #~ msgid "Original Foldername" #~ msgstr "Nome da pasta original" #~ msgid "folder" #~ msgstr "pasta" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Ativa a ordenação e renomeação de episódios." #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Ativar se os downloads não são colocados em suas próprias pastas." #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Ativar classificação e renomeação de arquivos nomeados com datas." #~ msgid "Are you sure you want to delete" #~ msgstr "Você tem certeza que quer apagar?" #~ msgid "Page" #~ msgstr "Página" #~ msgid "Close" #~ msgstr "Fechar" #~ msgid "Set Pause Interval" #~ msgstr "Definir Intervalo de Pausa" #~ msgid "Pause for 12 hours" #~ msgstr "Pausar por 12 horas" #~ msgid "Pause for 24 hours" #~ msgstr "Pausar por 24 horas" #~ msgid "Pause Interval" #~ msgstr "Intervalo de Pausa" #~ msgid "Left" #~ msgstr "Restantes" #~ msgid "Open Source URL" #~ msgstr "Abrir URL de Origem" #~ msgid "Storage" #~ msgstr "Armazenamento" #~ msgid "Plush Options" #~ msgstr "Opções Plush" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Enviar: .nzb .rar .zip .gz" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Ler Feed vai pegar o conteúdo do feed atual. Forçar " #~ "Download irá baixar todos os NZBs correspondentes agora." #~ msgid "Hour:Min" #~ msgstr "Hora:Min" #~ msgid "Access" #~ msgstr "Acesso" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Habilitar acesso HTTPS ao SABnzbd." #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Proteger o acesso ao SABnzbd com senha (recomendado)" #~ msgid "Misc" #~ msgstr "Diversos" #~ msgid "This field is required." #~ msgstr "Este campo é necessário." #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "" #~ "Abrir meu navegador de internet com a página do SABnzbd quando o programa " #~ "for iniciado." #~ msgid "Please enter a whole number." #~ msgstr "Por favor insira um número inteiro." #~ msgid "Step One" #~ msgstr "Primeiro Passo" #~ msgid "Step Two" #~ msgstr "Segundo Passo" #~ msgid "Step Three" #~ msgstr "Terceiro Passo" #~ msgid "Step Four" #~ msgstr "Quarto Passo" #~ msgid "Step Five" #~ msgstr "Quinto Passo" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "Ex. 119 ou 563 para SSL" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Falha ao remover nzb da fila de pós-processamento (id)" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Utilize V23 a não ser que o seu provedor exija outro!" #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Substituir caracteres inválidos em nomes de pastas por equivalentes (caso " #~ "contrário, removê-los)." #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Substituir caracteres inválidos em nomes de pastas" #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Quero que o SABnzbd seja acessado somente pelo meu computador." #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "" #~ "Quero que o SABnzbd seja acessado de qualquer computador em minha rede." #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "Após o SABnzbd ter reiniciado você será capaz de acessá-lo no seguinte " #~ "local: %s" #~ msgid "Notification classes" #~ msgstr "Classes de notificação" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "" #~ "Habilita classes de mensagens a serem relatadas (nenhuma, uma, ou múltiplas)" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "ATENÇÃO: Tarefa \"%s\" cancelada por causa de arquivo RAR criptografado" #~ msgid "OZnzb" #~ msgstr "OZnzb" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "" #~ "Enviar ao indexador resultados de validação dos downloads calculados " #~ "automaticamente." #~ msgid "Refer to https://www.oznzb.com/profile" #~ msgstr "Consulte https://www.oznzb.com/profile" #~ msgid "Site API Key" #~ msgstr "Chave API do site" #~ msgid "Automatic Feedback" #~ msgstr "Feedback Automático" #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Funcionalidades aprimoradas incluindo avaliações e informações extras de " #~ "status estão disponíveis quando conectado ao indexador OZnzb." #~ msgid "Enable OZnzb Integration" #~ msgstr "Ativar integração OZnzb" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Esta chave fornece a identidade ao indexador. Consulte " #~ "https://www.oznzb.com/profile." #~ msgid "Enable built-in unrar functionality." #~ msgstr "Ativa funcionalidade unrar interna." #~ msgid "Enable built-in unzip functionality." #~ msgstr "Ativa funcionalidade unzip interna." SABnzbd-2.3.2/po/main/ro.po0000644000000000000000000045004313217005051013451 0ustar 00000000000000# Romanian translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2016-07-29 16:20+0000\n" "Last-Translator: nicusor \n" "Language-Team: Romanian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:31+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Pornirea interfeţei-web nereuşită" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "Nu se poate găsi şablon web:%s, se încearcă şablon standard" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "modulul _yenc ... Negăsit!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "binar par2 ... Negăsit!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" "Versiunea ta de UNRAR este %s, noi recomandăm versiunea %s sau mai mare.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "binar unrar... Negăsit!" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "binar unzip... Negăsit!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "Fişier executabil 7za ... Indisponibil!" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Vă rugăm să fiţi conştienţi că numele gazdei 0.0.0.0 va avea nevoie de o " "adresa IPv6 pentru acces extern" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "Porturile HTTP și HTTPS nu pot fi aceleași" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "Dezactivează HTTPS din cauza lipsei fişierelor CERT şi KEY" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Nu am putu porni interfața web: " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "Nu pot contacta serviciul SABHelper" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s pornit" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Avertisment" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Eroare" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "Închidere SABnzbd terminată" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Numele gazdei nu este setat." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "" "Nu sunt conexiuni stabilite. Vă rugăm să stabiliţi cel puţin o conexiune." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Parolă ascunsă în ******, Vă rugăm să re-introduceţi" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Detalii server invalide" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "" "A depăşit timpul alocat : Încercaţi să activaţi SSL sau conectarea pe un " "port diferit." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "A depăşit timpul alocat" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Adresă server invalidă" #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Serverul a renunţat în timpul logării." #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Serverul necesită nume utilizator şi parolă" #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Conexiune Reuşită!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Autentificare nereuşită, verifică nume utilizator/parolă." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "Prea multe conexiuni, vă rugăm să întrerupeţi descărcarea sau să încercaţi " "din nou mai târziu" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Nu pot determina reultatul conexiunii (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Semnal %s prins, salvez şi ies..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Eroare fatală la salvare" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Încerc să descarc NZB de la %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Salvarea %s nereuşită" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Nu pot crea fişier temporar pentru %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Încerc să setez starea unui server nexistent %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Eroare în tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Încărcarea %s nereuşită" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Încărcarea lui %s a eșuat cu eroarea %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Notificări Test" #: sabnzbd/api.py msgid " Resolving address" msgstr " Reolvare adresă" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Niciunul" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Implicit" #: sabnzbd/api.py msgid "unknown" msgstr "necunoscut" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Compilarea unei căutări regex nereuşită: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "Prea puţin spaţiu disc forţez PAUZĂ" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Disc plin! Pauză Forţată" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Eroare disc la crearea fişierului %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Eroare fatală în Assembler" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Terminat, encriptare detectată" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "ATENȚIE: În fișierul RAR \"%s\" sunt extensii nedorite. Fișierul nedorit " "este %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "Extensii fișier nedorite în fișierul rar %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Oprit, extensii nedorite detectate" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "ATENȚIE: Sarcina \"%s\" întrearuptă datorită ratingului (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "ATENȚIE: Sarcina \"%s\" anulată datorită ratingului (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Abandonat, filtru de rating potrivit (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s lipsă" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "video" #: sabnzbd/assembler.py msgid "audio" msgstr "audio" #: sabnzbd/assembler.py msgid "spam" msgstr "spam" #: sabnzbd/assembler.py msgid "passworded" msgstr "parolat" #: sabnzbd/assembler.py msgid "downvoted" msgstr "vot negativ" #: sabnzbd/assembler.py msgid "keywords" msgstr "cuvinte cheie" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Cotă epuizată, întrerupem descărcarea" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s nu este o adresă email validă" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Adresă server necesară" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Nu pot crea %s dosar %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Nu pot scrie în fişierul INI %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Nu pot crea copie de rezervă pentru %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Parolă %s codificată greşit" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s nu este o valoare octală corectă" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "cale UNC \"%s\" nu este premisă aici" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Eroare: Lungimea cale ar trebuie să fie sub %s." #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Eroare: Coada nu este goală, nu pot schimba dosar." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "" "Nu pot scrie în baza de date ISTORIC, verificaţi permisiunile de acces." #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "Bază de date Istoric coruptă, creat un nou fişier gol" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "Comandă SQL Nereuşită, vedeţi jurnal" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Închidere bază de date nereuşită, vedeţi jurnal" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Jurnal istoric stagii invalid pentru %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Decodarea %s nereuşită" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Articoul yEnc invalid în %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Eroare Necunoscută în timpul decodării %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => lipsă de pe toate serverele, ignorare" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Finalizat" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "Dezarhivat %s fişierele/dosarele în %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "Nu pot citi %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Eroare adăugare %s, ştergem" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Eroare ştergere %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Nu pot citi Dosar Urnărire %s" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Reluare" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Întrerupt" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Trebuie să seta-ţi lățimea de bandă maximă înainte de a seta o limită de " "viteză." #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Serverul %s va fi ignorat pentru %s minute" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Nu am putu inițializa %s@%s din cauza următorului motiv: %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "Prea multe conexiuni la serverul %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Partajare cont probabilă" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Autentificare nereuşită la serverul %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Nu mă pot conecta la serverul %s [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "Conectare %s@%s eșuată, mesaj=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Serverul %s necesită utilizator/parolă" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Eroare suspectă în sistemul de descprcare" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Închidere" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Conectare server mail nereuşită" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "Iniţializare conexiune TLS nereuşită" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "Serverul nu a răspuns în mod corect la cererea de inițiere" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Autentificare server mail nereuşită" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Nu am găsit nici o metodă potrivită de autentificare" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "Eroare necusnoscută la autentificarea la serverul de mail" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Trimitere email nereuşiă" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Închidere conexiune mail nereuşită" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "Email reuşit" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Nu pot trimite, informații necesare lipsă" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Nu pot gasi şabloane email în %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Destinatar necunoscut, niciun email trimis" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Codificare invalidă a şablonului email %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Şabloane email negăsite" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "From: %s\n" "To: %s\n" "Date: %s\n" "Subject: SABnzbd raporteaza Disc Plin\n" "\n" "Salut,\n" "\n" "SABnzbd sa oprit din descarcare, deoarece discul este aproape plin.\n" "Va rugam sa faceti loc si reluati SABnzbd manual.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "Atenţie:LOCALHOST este ambiguu, folosiţi o adresă IP numerică" #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Adresa server \"%s:%s\" nu este validă" #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "Utilizatorul s-a autentificat în interfața web" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "Utilizator logat" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Cheie Sesiune lipsă" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Eroare: Cheie Sesiune Necesară" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Eroare: Cheie Sesiune Incorectă" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "Cheie API lipsă, vă rugăm să introduceţi cheia api de la Configurare-" ">General în programul dumneavoastră terţ" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "Cheie API incorectă, Folosiţi cheia api din Configurare->General în " "programul dumneavoastră terţ:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Autentificare lipsă, vă rugăm să introduceţi numele de utilizator/parola de " "la Configurare->General în programul dumneavoastră terţ:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Încearcă noua noastră interfață Glitter! Un design nou și optimizat pentru " "modul desktop și dispozitive mobile . Dute în Configurare -> General și " "modifică tipul de interfață." #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
Închidere SABnzbd terminată.
Aşteptaţi timp de aproximativ 5 " "secunde şi apoi faceţi clic pe butonul de mai jos.

Reîmprospătează
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Flux" #: sabnzbd/interface.py msgid "Daily" msgstr "Zilnic" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "Luni" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Marţi" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Miercuri" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Joi" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Vineri" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Sâmbătă" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Duminică" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "dezactivat" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Server nedefinit!" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Parametru Incorect" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Înapoi" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "EROARE:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Valoare incorectă pentru %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "d" #: sabnzbd/misc.py msgid "h" msgstr "h" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Nu pot crea dosarul %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "dosarul %s: eroare accesare %s" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Facere nereuşită (%s)" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Mutare %s în %s nereuşită" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Eroare la crearea cheiei şi certificatlui SSL" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Nu pot schimba permisiunile lui %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Rulare script" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Post-Procesarea a fost abandonată (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Script" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Numărul de arhive încorporate este prea mare [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Unim" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Secvenţă incompletă de unire fişiere" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Unirea fişierului %s nereuşită" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Eroare \"%s\" în timpul unirii fişierelor" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Eroare \"%s\" în timpul file_join a %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] Unit %s fişierele" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Dezarhivare nereuşită, %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Eroare \"%s\" în timpul dezarhivării fişierelor RAR" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Eroare \"%s\" în timpul rar_unpack a %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Ştergere %s nereuşită!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Încerc unrar cu parola \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Dezarhivare nereuşită, arhiva necesită o parolă" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Dezarhivare" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Dezarhivează" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Dezarhivare nereuşită, nu pot găsi %s" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "EROARE: nu pot găsi \"%s\"" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Dezarhivare nereuşită, eroare CRC" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "EROARE: CRC nereuşit în \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "Dezarhivare nereuşită, eroare scriere sau disc plin?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "EROARE: eroare scriere (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Dezarhivare eșuată, calea este prea lungă" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "EROARE: calea este prea lungă (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Dezarhivare nereuşită, vezi jurnal" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "EROARE: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Fișier RAR ce poate fi folosit" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s fişiere în %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Eroare \"%s\" în timpul rulării unzip() pe %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Încerc 7zip cu parola \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "Setul 7ZIP \"%s\" este incomplet, nu pot dezarhiva" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Nu pot dezarahiva %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Verificare Rapidă" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Repară" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Verficare Rapidă OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Pornire Reparare" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "Verificarea Par eșuată pentru %s, dar VerificareaRapidă reușită!" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Reparare nereuşită, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Eroare %s în timpul rulării par2_repair pe setul %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Eroare \"%s\" în timpul rulării par2_repair pe setul %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] PAR2 a primit opţiuni incorecte, verifică setările Configurare-" ">Comutatoare" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Verificat în %s, toate fişierele sunt corecte" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Verificat în %s, reparare necesară" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "Descărcare %s blocuri..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Descărcare" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "Reparare nereuşită, blocuri reparare insuficiente (%s mai puţin)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Se repară" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Reparat în %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Disc plin" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Se verifică" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Se verifică" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Acest server nu permite SSL pe acest port" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Pornire/Închidere" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "NZB-uri Adăugate" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Post-procesare pornită" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Sarcină terminată" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Sarcină eșuată" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Coadă finalizată" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Alte Mesaje" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Indisponibil" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Nu am putu trimite mesajul Prowl" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Răspuns greșit de la Pushover (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Nu am putut trimite mesajul de pushover" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Răspuns greșit de la Pushbullet (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Nu am putu trimite mesajul pushbullet" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "" "Scriptul a returnat codul de ieșire %s și rezultatele următoare \"%s\"" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "Scriptul de notificare \"%s\" nu există" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "Nu am putut trimite notificări în Fereastră" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "" "Coadă de descărcare veche detectată, utilizează Stare->Reparare pentru a " "converti coada" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Fişier coadă găsit incompatibil, nu pot înainta" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Eroare încărcare %s, fişier corupt detectat" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "Nu am putut reporni NZB după pre-verificare (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB adăugat în coadă" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Codificare Necunoscută" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Fişierul %s este gol , ignorăm" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Importare %s a fişierelor de la %s nereuşită" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Fişier NZB incomplet %s" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Fişier NZB invalid %s, ignorăm (motiv=%s, line=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Fişier NZB gol %s" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Ignorăm duplicat NZB \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Întrerupem duplicat NZB \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Anulat nu poate fi finalizat" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "DUPLICAT" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "ENCRIPTAT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "PREA MARE" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "INCOMPLET" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "NEDORIT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "FLTRAT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "AŞTEAPTĂ %s sec" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "SE PROPAGHEAZĂ %s min" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Descărcat în %s cu o medie de %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Vârsta" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s articolele au fost incorecte" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s articolele au fost lipsă" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s articolele au avut duplicate diferite" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "Articolele %s au fost eliminate" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Eroare importare %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Atenționări" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Inactiv" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Configurare" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Coadă" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Goleşte Coadă" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Istoric" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Şterge Istoricul" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Limitare de Viteză" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Pauză" #: sabnzbd/osxmenu.py msgid "min." msgstr "min." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Reia" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Scanează dosar urmărire" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Citește toate feed-urile RSS" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Dosar Complet" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Dosar Incomplet" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Depanare" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Repornește" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Reporneşte fără autorizare" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Ieșire" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Pune la Coadă Primele 10 Obiecte" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Gol" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Istoric Ultimele 10 Obiecte" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Versiune nouă disponibilă" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Dute la vrăjitor" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Se oprește..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Problemă cu" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd are nevoie de un tcp/ip port liber pentru serverul său " "intern.
\n" " Portul %s de pe %s a fost încercat , dar nu este disponibil.
\n" " Alt program foloseşte portul sau SABnzbd este deja pornit.
\n" "
\n" " Vă rugăm să reporniţi SABnzbd cu un număr de port diferit." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "" "Dacă primiţi acest mesaj de eroare din nou, vă rugăm să încercaţi un alt " "număr.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd are nevoie de o adresă gazdă validă pentru serverul său " "intern.
\n" " Dvs. a-ţi specificat o adresă invalidă.
\n" " Valori sigure sunt localhost şi 0.0.0.0
\n" "
\n" " Vă rugăm să reporniţi SABnzbd cu o adresă gazdă bună." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd a detectat informaţii salvate de la o altă versiune SABnzbd
\n" " dar nu poate să refolosească informaţiile de la cealaltă versiune de " "program.

\n" " Ar fi bine să terminaţi coada mai întâi cu cealaltă versiune de " "program.

\n" " După aceia , porniţi programul cu opţiunea \"--clean\".
\n" " Aceasta va şterge coada curentă şi istoricul!
\n" " SABnzbd citeşte fişierul \"%s\"." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd nu poate găsi fişierele de la interfaţa-web %s.
\n" " Vă rugăm să reinstalaţi programul din nou.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd a detectat o eroare fatală:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd a detectat că fişierul sqlite3.dll lipseşte.

\n" " Unele antivirusuri şterg acest fişier.
\n" " Vă rugăm să verificaţi antivirusul , încercaţi să reinstalaţi SABnzbd şi " "plângeţivă autorului antivirusului.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Apasă Start+R şi scrie linia (exemplu):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Deschide fereastra Terminal şi scrie linia (exemplu):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Aplicaţia nu a pornit!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Eroare fatală" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "Nu pot porni navigatorul web, probabil nu a fost găsit" #: sabnzbd/panic.py msgid "Access denied" msgstr "Acces interzis" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Eroare %s: Trebuie să furnizaţi un nume utilizator şi parolă valid" #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "Descărcarea ar putea eşua, doar %s din %s disponibil" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Descărcare euată, - Nu este pe serverul(ele) dumneavoastră" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Nici o post-procesare din cauza verificării nereuşite" #: sabnzbd/postproc.py msgid "Moving" msgstr "Mutare" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "Trimis %s în coadă" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Eroare redenumire \"%s\" în \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Nu am putu muta fişier" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Rulare script utilizator %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "Durată %s" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Codul de ieșire a scriptului este %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Mai mult" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Post Procesare Nereuşită pentru %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "vezi fişier jurnal" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Descărcarea a eșuat" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Ştergerea lui %s nereuşită." #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Eroare ştergere dosar curent (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Descărcare terminată" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Nu pot crea dosar final %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Post-procesare" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Niciun set par2" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Încerc verificare SFV" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Unele fişiere nu au fost verificate corect cu \"%s\"" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Verificare reuşită cu fişierele SFV" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "Parolat" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Ştergerea %s nereuşită" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Punere sistem în hibernare nereuşită" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Punere sistem în aşteptare nereuşită" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Eroare la oprirea sistemului" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "Id-ul indexului (%s) nu a fost găsit pentru fișierul de rating" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Adresă server" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "Cheie API" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Descriere flux RSS incorectă \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Descărcare %s: %s din RSS nereuşită" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Autentificare invalida pentru flux %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "Eroare la server (codul server %s); nu am putu lua %s în data de %s" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "Serverul %s utilizează un certificat HTTPS nesigur" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "Fluxul RSS %s a fost gol" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Fulx RSS incompatibil" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Valoare RSS gasită a fost goală (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Arată interfața" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Deschide dosar descărcări complete" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Închidere" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Rămas" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Adaugă NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Programator Greşit %s la %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Acţiune necunoscută: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Planificare pentru un server inexistent %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Descarcă" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Uneşte fişierele" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Sursă" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Servere" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Nereuşit" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Nereuşit" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "Se așteaptă" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Reparare..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Dezarhivare..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Mutare..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Rulare script..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Descărcare blocuri extra..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Verificare Rapidă..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Verificare..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Descărcare" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "Întârziere de propagare" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Frecvenţă" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Acțiune" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Argumente" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Sarcină" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "dezactivează server" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "activează server" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Limitare de Viteză" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Pauză Toate" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Pauză post-procesare" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Reia post-procesare" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Citeşte fluxuri RSS" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Elimină sarcini nereuşite" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Elimină sarcinile finalizate" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Întrerupte sarcinile cu prioritate redusă" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Întrerupe sarcinile cu prioritate normală" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Întrerupe sarcinile cu prioritate ridicată" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Reia sarcinile cu prioritate redusă" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Reia sarcinile cu prioritate normală" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Reia sarcinile cu prioritate ridicată" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Activează gestionarea cotelor" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Dezactivează gestionarea cotelor" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Oprit" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Foarte scăzută" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Moderat" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normal" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Ridicată" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Urgență" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Scăzută" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "MB" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "GB" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "oră" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "ore" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "min" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "minute" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "sec" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "secunde" #: sabnzbd/skintext.py msgid "day" msgstr "zi" #: sabnzbd/skintext.py msgid "days" msgstr "zile" #: sabnzbd/skintext.py msgid "week" msgstr "săptămână" #: sabnzbd/skintext.py msgid "Month" msgstr "Lună" #: sabnzbd/skintext.py msgid "Year" msgstr "An" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Zi din lună" #: sabnzbd/skintext.py msgid "This week" msgstr "Săptămâna aceasta" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Luna aceasta" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "Azi" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Total" #: sabnzbd/skintext.py msgid "on" msgstr "activat" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parametrii" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Versiune Python" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Pagină de pornire" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "sau" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Gazdă" #: sabnzbd/skintext.py msgid "Comment" msgstr "Comentariu" #: sabnzbd/skintext.py msgid "Send" msgstr "Trimite" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Anulează" #: sabnzbd/skintext.py msgid "Other" msgstr "Altele" #: sabnzbd/skintext.py msgid "Report" msgstr "Raportează" #: sabnzbd/skintext.py msgid "Video" msgstr "Video" #: sabnzbd/skintext.py msgid "Audio" msgstr "Audio" #: sabnzbd/skintext.py msgid "Not used" msgstr "Neutilizat" #: sabnzbd/skintext.py msgid "or less" msgstr "sau mai puțin" #: sabnzbd/skintext.py msgid "Log in" msgstr "Autentificare" #: sabnzbd/skintext.py msgid "Log out" msgstr "Deconectare" #: sabnzbd/skintext.py msgid "Remember me" msgstr "Ține-mă minte" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "Instrumentul de descărcare automată usenet" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Salvează" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Sunteţi sigur?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Ştergeţi toate fişierele descărcate?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Pagina de pornire" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Configurare" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Stare" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Ajutor" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Forum" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "Probleme" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "General" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Directoare" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Comutatoare" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Planificare" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Notificări" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "Email" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Categorii" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Sortare" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Special" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Caută" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Dosar Descărcare" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "ÎNTRERUPT" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "Articole %s în cache (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Încărcare sistem" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Versiune nouă %s disponibilă la" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Sunteţi sigur că doriţi să inchideţi SABnzbd?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Adaugă" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Adaugă fişier" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Categorie" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "În curs de procesare" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Prioritate" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Reparare" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Dezarhivare" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Ştergere" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "U" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "D" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Forțează" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Stop" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "Introdu URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "La terminarea coadei de descărcare" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Închide PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "Repaus PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Hibernare PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Închide SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Limită de Viteză" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Pauză timp de" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Ordine" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Nume" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "Timp Estimat" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "Vârstă" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Şterge" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Reîncearcă" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Acțiuni" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Script-uri" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Ştergeţi toate obiectele din coadă?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Şterge NZB-uri" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Şterge NZB-uri & Fişiere Şterse" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Reîncearcă toate sarcinile eșuate" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Şterge NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Şterge NZB & Fişiere Şterse" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "din" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Articole lipsă" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Cotă rămasă" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "manual" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Resetează Cota acum" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Ştergeţi toate obiectele complete din Istoric?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Ascunde detaliile" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Arată detalii" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Arată Nereuşite" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Arată toate" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Mărime" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Şterge NZB-uri nereuşite" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Şterge NZB-uri Nereuşite & Fişiere Şterse" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Şterge NZB-uri Complete" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "NZB Suplimentar Opţional" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Cale" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Reîncearcă toate eșuate" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Reîncearcă toate" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus/spam" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "Dincolo de retenție" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Altă problemă" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Forţează Deconectarea" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Acesta va trimite un email test către contul dvs." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Arată Jurnalizarea" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Email Test" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Jurnalizare" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Erori/Avertismente" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ Info" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ Depanare" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Conexiuni" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Ultimele Avertizări" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "Şterge" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Deblochează" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Identificator Articol" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Set fişiere" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Când" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Tip" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Activat" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Panou de Control" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Conectare eșuată!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Adresa IPv4 locală" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Adresa IPv4 publică" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "Adresa IPv6" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Server de nume/Căutare DNS" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "Model CPU" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "Perfromanță Sistem (Pystone)" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Viteză de descărcare director" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Vitează completă director" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Viteză de scriere" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "Nu am putut scrie. Verifică dacă director poate fi modificat." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Click pe butonul de Repetare test pentru a determina" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Repetă test" #: sabnzbd/skintext.py msgid "Config File" msgstr "Fişier Configurare" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Cache Folosit" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Acest lucru va reporni SABnzbd.
Folosiţi-l atunci când credeţi că " "programul are o problemă de stabilitate.
Descărcarea va fi oprită " "înainte de repornire şi reluată ulterior." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" "
Dacă este activată autentificarea v-a trebuie să vă logați din nou." #: sabnzbd/skintext.py msgid "Advanced" msgstr "" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Sunt sarcini orfane în dosarul de descărcare.
Puteţi alege în a le " "şterge (inclusiv fişierele) sau a le trimite înapoi în coadă." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "Butonul \"Reparare\" va reporni SABnzbd şi face o reconstrucţie completă
a conţinutului coadei de descărcare , menţinând fişierele deja " "descărcate.
Acest lucru va modifica ordinea în coada de descărcare." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Modificările nu au fost salvate, şi vor fi pierdute." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" "Atunci când modificați adresa IP sau dacă SABnzbd este repornit sesiunea " "dumneavoastră va expira." #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Activează Unzip" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "Activează 7zip" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" #: sabnzbd/skintext.py msgid "Version" msgstr "Versiune" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Durata Funcţionării" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Server Secundar" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Citeşte Ajutorul Wiki despre asta !" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Repornim SABnzbd..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Modificările vor necesita repornirea SABnzbd!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "Server Web SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "Gazdă SABnzbd" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Nume Gazdă unde SABnzbd va asculta." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "Port SABnzbd" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Portul pe care SABnzbd îl va asculta." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Interfață Web" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Alege o temă." #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "Nume Utilizator SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Nume Utilizator autentificare opţional" #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "Parolă SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Parolă autentificare opţională" #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "Activează HTTPS" #: sabnzbd/skintext.py msgid "not installed" msgstr "neinstalat" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Permite acesarea interfeţei de la o adresă HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "Port HTTPS" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Dacă e gol, portul standard va asculta doar în HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "Certificat HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Nume fişier sau cale Certificat HTTPS." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "Cheie HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Nume fişier sau cale Cheie HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "Certificate Cheie HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Nume fişier sau cale cheie HTTPS." #: sabnzbd/skintext.py msgid "Tuning" msgstr "Optimizări" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "Interval Verficare RSS" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Interval verificare (în minute, cel puţin 15). Inactiv când se foloseşte " "Planificatorul!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Viteză maximă a conexiunii" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Procent din viteza conexiunii" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "Ce procent din viteza conexiuni poate fi utilizat de SABnzbd, ex. 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Limită Cache Articole" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Stochează articolele în memorie pentru a reduce acesul disc.
În " "octeţi, opţional urmaţi de K,M,G. De exemplu : \"64M\" sau\"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Listă Curăţenie" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Listă de extensii fișiere ce trebuie să fie șterse după descărcare.
De " "exemplu: nfo or nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Salvează Modificările" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Resetează" #: sabnzbd/skintext.py msgid "Language" msgstr "Limbă" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Alegeţi o limbă interfaţă web." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "Această cheie va oferi programelor terţe acces deplin la SABnzbd." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "Cheie NZB" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "Această cheie va permite programelor terţe să adauge NZB-uri în SABnzbd." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Generează o Cheie Nouă" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "Cheie API sau Cod QR" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Listă de rețele locale" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Toate rețelele locale încep cu acest prefixe (de regulă \"192.168.1.\")" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Acces extern la internet" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" #: sabnzbd/skintext.py msgid "No access" msgstr "Fără acces" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Adaugă fișiere NZB " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (fără Configurare)" #: sabnzbd/skintext.py msgid "Full API" msgstr "API Complet" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Interfață Web completă" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "Doar accesul extern necesităr autentificare" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "NOTĂ:Dosarele vor fi create automat când se Salvează. Puteţi " "utiliza căi absolute pentru a salva în afara dosarelor implicite." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Dosare Utilizator" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Răsfoire" #: sabnzbd/skintext.py msgid "In" msgstr "În" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Dosar Descărcare Temporar" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Locaţie de stocare a descărcărilor neprelucrate.
Poate fi schimbată " "doar atunci când coada este goală." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Minim de Spaţiu Liber pentru Dosar Descărcare Temporar" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Auto-pauză când spaţiul liber este sub această valoare.
În octeţi, " "urmaţi opţional de K, M, G, T. De exemplu: \"800M\" sau \"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Dosar Descărcări Finalizate" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Locație pentru stocare , a descărcărilor procesate complet.
Poate fi " "suprascris de categoriile definite de utilizator." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Permisiuni pentru descărcări finalizate" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Setează permisiunile pentru fişierele/directoarele finalizate.
În " "valori octale. De exemplu: \"755\" sau \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Dosar Monitorizat" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Dosar pentru supraveghere fişiere .nzb.
Scanează de asemenea şi " "arhivele .zip .rar .tar.gz de fişiere .nzb." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Viteză Scanare Dosar Monitorizat" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Numărul de secunde între scanarea de fişiere .nzb." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Dosar Şabloane Email" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Dosar ce conţine şabloane email utilizator." #: sabnzbd/skintext.py msgid "Password file" msgstr "Fișier parole" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "Fişier ce conţine parole pentru fişiere RAR encriptate." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Dosare Sistem" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Dosar Administrativ" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Locaţia coadei admin şi istoricul bazei de date.
Poate fi folosit " "doar când coada e goală." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "Informaţiile vor nu vor fi mutate. Necesită repornire SABnzbd!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Dosar Jurnal" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Locaţie a fişierelor jurnal ale SABnzbd.
Necesită repornire " "SABnzbd!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr "Dosar Copie de Siguranţă .nzb" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Locaţie unde fişierele .nzb vor fi stocate." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Dosar de Bază Implicit" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Descarcă toate fișierele par2" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Activează dezarhivarea recursivă" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Dezarhivează arhivele (rar, zip, 7z) conținute în alte arhive." #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Ignoră orice director din interiorul arhivelor" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Toate fișierele merg într-un singur director" #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Ia Articole doar din Vârful Coadei" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Activează pentru folosire de memorie mai puţină. Dezactivaţi pentru a " "preveni ca sarcinile lente să blocheze coada." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Post-Procesează Doar Sarcinile Verificate" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "" "Execută post-procesarea doar dacă sarcina a trecut toate verificările PAR2." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Acțiuni când se descarcă un RAR encriptat" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "În cazul \"Întrerupere\", dumneavoastră trebuie să introduceți parola și să " "reluați sarcina." #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Detectează Descărcări Duplicate" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Detectează episoade duplicate în seriale" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Ignoră" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Renunță" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Acțiune când se detectează o extensie nedorită" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "Acțiune când se detectează extensie nedorită într-un fișier RAR" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Extensii nedorite" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Listă cu toate extensiile nedorite. De exemplu: exe or exe, com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Activează verficări SFV" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Fă o verificare extra bazată pe fişiere SFV" #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Sarcina cu script a utilizatorului a eșuat" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Când un script de utilizator returnează o ieșire diferit de codul de ieșire, " "sarcina v fi marcată ca fiind nereușită." #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "La eroare, încearcă NZB alternativ" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "Unele server oferă o alternativă dacă un NZB eșuează." #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Activează redenumire dosar" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Foloseşte nume temporare în timpul post procesării. Dezactivaţi când " "sistemul dvs. nu gestionează aceasta corect." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Script utilizator Pre-Coadă" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Folosit înainte ca un NZB să intre în coadă." #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Parametri Extra PAR2" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Parametri Nice" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "Parametri IONice" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Deconectează când Coada e Goală" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "" "Deconectează de la serverul(ele) Usenet când coada e goală sau în pauză." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Sortează după Vârstă" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Sortează automat obiectele dupa vârstă (medie)." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" "Articolele vor fi întrerupte până ce vor avea cel puțin vechimea aceasta. " "Dacă setați prioritatea descărcării ca Forțat evitați această întârziere." #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Verifică Versiuni Noi" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Verificare săptămânală versiuni noi SABnzbd." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "Testeaza şi versiuni de încercare" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Înlocuieşte Spaţiile din Numele Dosarelor" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Înlocuieşte spaţiile cu _ în numele dosarelor." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Înlocuieşte punctele din Numele Dosarelor" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Înlocuieşte puntele cu spaţii în numele dosarelor." #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Fă Windows compatibil" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "Pentru servere: asigurați-vă că numele sun comparibile cu Windows" #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Porneşte Navigator Web la Pornire" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Porneşte navigatorul web implicit când se porneşte SABnzbd." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Întrerupe Descărcarea în Timpul Post-Procesare" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Întrerupe descărcare la începerea post procesării şi reporneşte când e " "terminată." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Ignoră Monstre" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Ignoră fişiere monstră (de ex. monstre video)" #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Şterge după descărcare" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" #: sabnzbd/skintext.py msgid "Server" msgstr "Server" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Post procesare" #: sabnzbd/skintext.py msgid "Naming" msgstr "Redenumire" #: sabnzbd/skintext.py msgid "Quota" msgstr "Cotă" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indexare" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Cât de mult poate fi descărcat în acestă lună (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Zi resetare" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "În ce zi a lunii sau săptămână (1=Luni) ISP dumneavoastră resetează cota? " "(Opțional cu hh:mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Auto repornire" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "Se reia descărcarea după resetarea cotei?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Perioadă Cotă" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "Cota se resetează în fiecare zi, săptămână sau lună ?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Verifică înainte de descărcare" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Încearcă să prezici decărcarea cu succes înaintea descărcării reale (mai " "lent!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Număr Maxim reîncercări" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Număr Maxim reîncercări pe server" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Anulează sarcini care nu pot fi terminate" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Atunci când e clar că o sarcină va eșua din cauza lipsei de date pe " "server(e), anulează sarcina" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Activează Filtrare" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Acțiune când se descarcă în baza de reguli de filtrare." #: sabnzbd/skintext.py msgid "Abort If" msgstr "Renunță Dacă" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Altfel Întrerupe Dacă" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Rating Video" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Rating Audio" #: sabnzbd/skintext.py msgid "Spam" msgstr "Spam" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Confirmat" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Mai multe voturi pozitive ca negative" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Cuvinte cheie din Titlu" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Listă separată prin virgulă" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Server de load-balancing" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Previne load-balancing" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Permite load-balancing" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Permite load-balancing cu o optimizare pentru IPv6" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "Util dacă un server de știri are mai mult decât o adresă IPv4/IPv6" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Adaugă Server" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Descriere server" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Port" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Nume de Utilizator" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Parolă" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Timp Expirare" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Timp Retenţie" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Dezactivat" #: sabnzbd/skintext.py msgid "Minimal" msgstr "" #: sabnzbd/skintext.py msgid "Strict" msgstr "" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "" "0 este prioritatea cea mai ridicată, 100 este prioritatea cea mai scăzută" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Opţional" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Activează" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Şterge Server" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Test Server" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Resetează Statistici" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Testez detalii server..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Descărcat" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Trimite Grup" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Trimite comanda group înainte de a cere articole." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Utilizează acest server doar pentru aceste categorii." #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" "Nici unul din serverele activate au categoria 'Default' delectată. Sarcinile " "din coada de descărcare care nu au desemnate o categorie corespunzătoare " "serverelor nu vor fi descărcate." #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Note personale" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Adaugă Planificare" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Planificări Curente" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "Caseta de lângă numele fluxului trebuie să fie selectată pentru ca fluxul să " "fie verificat de obiecte noi automat.
Când un flux este adăugat , el va " "lua doar obiectele noi şi nu cele deja existente, cu excepţia când apăsaţi " "\"Descărcare Forţată\"." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Citeşte Flux" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Descărcare Forţată" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Filtru" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Acceptă" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Respinge" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Necesită" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "NecesităCategoria" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Cel puțin" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Cel mult" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "De la SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Potrivite" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Nepotrivit" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Descărcate" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Citeşte Toate Fluxurile Acum" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "Notificări Email Sarcină Terminată" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Niciodată" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Întotdeauna" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Doar-erori" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Notificări Disc Plin" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "Trimite email când discul este plin şi SABnzbd este întrerupt." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Trimite notificări RSS" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "Trimite email când un flux RSS adaugă sarcini în coadă." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "Server SMTP" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Setează serverul dvs. ISP pentru trimitere email." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "Destinatar Email" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "Adresă de email către care se trimite email." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "Expeditor Email" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Cine ar trebui să spunem că a trimis email?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "Nume Cont OPŢIONAL" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Pentru email autentificat, nume cont." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "Parolă Cont OPŢIONAL" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Pentru email autentificat, parola." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Activează Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Trimite notificări Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Foloseşte doar pentru server Growl de la distanţă (gazdă:port)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Parolă server" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Parolă opţională server Growl" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "Activează NotifyOSD" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Trimite notificări către NotifyOSD" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Centru Notificări" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Trimite notificări la Centru Notificări" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Activează notificări Windows" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Notificări Windows" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotificăOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Activează notificări Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Necesită cont Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "Cheie API pentru Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Cheie API personală pentru Prowl (necesară)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Activează notificări Pushover" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Necesită cont Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Token de Aplicație" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Token de Aplicație (necesar)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Cheie Utilizator" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Cheie Utilizator (necesară)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Dispozitiv(e)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Dispozitiv(e) la care să se trimită mesajul" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Activează notificare Pushbullet" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Necesită un cont Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Cheie API personală" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Cheie personală API Pushbullet (necesară)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Dispozitiv" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Dispozitiv la care să se trimită mesajul" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "Scipt de Notificare" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "Activează scriptul de notificare" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "Execută script personalizat" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "Ce script să fie executat pentru notificări?" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Finalizarea unei căi cu un asterix * va preveni crearea de dosare sarcini." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Dosarele relative se bazează pe" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Dosar/Cale" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Sortare Seriale" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Activează Sortare TV" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Model Cheie" #: sabnzbd/skintext.py msgid "Clear" msgstr "Şterge" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "" #: sabnzbd/skintext.py msgid "Presets" msgstr "Presetări" #: sabnzbd/skintext.py msgid "Example" msgstr "Exemplu" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Activează Sortare Filme" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Păstrează descărcările suplimentare în dosare extra" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Categorii Afectate" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Semnificaţie" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Șablon" #: sabnzbd/skintext.py msgid "Result" msgstr "Rezultat" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Dosar Sezon" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Dosar Sezon" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Dosar Episod" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Dosar Episod" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Titlu" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Nume Film" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Nume.Film" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Nume_Film" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Nume Serial" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Nume.Serial" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Nume_Serial" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Număr Sezon" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Număr Episod" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Nume Episod" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Nume.Episod" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Nume_Episod" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Extensie fișier" #: sabnzbd/skintext.py msgid "Extension" msgstr "Extensie" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Număr Parte" #: sabnzbd/skintext.py msgid "Decade" msgstr "Deceniu" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Nume de Fişier Original" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Litere Mici" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEXT" #: sabnzbd/skintext.py msgid "text" msgstr "text" #: sabnzbd/skintext.py msgid "file" msgstr "fișier" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Şir Caractere Sortare" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Etichetă Multi-părţi" #: sabnzbd/skintext.py msgid "In folders" msgstr "În dosare" #: sabnzbd/skintext.py msgid "No folders" msgstr "Fără dosare" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Sortare Dată" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Activează Sortare Dată" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Arată Nume dosar" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "Dosar An-Lună" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Dosare Zilnice" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "ajustare nume fişier" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Rezultat Procesat" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Opţiuni folosite rar. Pentru explicaţiile şi semnificaţia lor, click pe " "meniul Ajutor şi vizitează pagina Wiki.
Nu modificaţi aceste setări fără " "a verifica mai întâi pagina Wiki , pentru că unele pot cauza probleme " "serioase .
Valorile originale sunt în paranteze ." #: sabnzbd/skintext.py msgid "Values" msgstr "Valori" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Editează Detalii NZB" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Şterge" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Vârf" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Sus" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Jos" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Coadă" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Toate" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Inversează" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Nume de fișier" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Subiect" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Selecţie" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Pauză timp de 5 minute" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Pauză timp de 15 minute" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Pauză timp de 30 minute" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Pauză timp de o oră" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Pauză timp de 3 ore" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Pauză timp de 6 ore" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "rămas" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Spațiu liber" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Dosar Temporar" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Operaţii-Multiple" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Ține-ți tasta shift pentru a selecta un interval" #: sabnzbd/skintext.py msgid "Check all" msgstr "Selectează tot" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Repornește SABnzbd" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Opțiuni stare și interfață" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Sau trage fișierele în fereastră!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Am pierdut conexiunea cu SABnzbd.." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "În cazul repornirii SABnzbd acest ecran va dispărea în mod automat!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "ATENŢIE:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Descarcă" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Rată actualizare" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Folosește setările globale de interfață" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Limită maximă la coadă" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Limită maximă la Istoric" #: sabnzbd/skintext.py msgid "Date format" msgstr "Format dată" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Coloană extra la Coadă" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "Coloană extra de istoric" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "pagină" #: sabnzbd/skintext.py msgid "Loading" msgstr "Se încarcă" #: sabnzbd/skintext.py msgid "articles" msgstr "articole" #: sabnzbd/skintext.py msgid "Rename" msgstr "Redenumește" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Coadă reparare" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Arată conexiuni active" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Sarcini orfane" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Trimite înapoi la coadă" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Șterge tot" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Reîncearcă toate" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Descarcă NZB din URL" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "Încarcă NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Opţional specifică un nume de fişier" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Formate: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Trimite" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Dechide URL Informaţii" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Trimis. Vă mulțumim!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Nimic selectat!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Elimină toate fișierele selectate" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Ascunde/arată fișierele finalizate" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Vezi Jurnal Script" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Actualizare Disponibilă!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" "Stocarea locală (module cookie) sunt dezactivate în browserul dumneavoastră, " "setările de interfață vor fi pierdute la încridegea browserului!" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Personalizat" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "Aspect compact" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "Interfață tabelară
(coadă și istoric separate)" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Viteză" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Confirmă Ştergere Coadă" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Confirmă Ştergere Istoric" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Cât timp sau până când doriți să întrerupeți? (în Engleză!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Ne pare rău, nu am putut interpreta informațiile. Încearcă din nou." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Pauză timp de..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Reîmprospătează" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Sortează după Vârstă Cel mai Vechi→Cel mai Nou" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Sortează după Vârstă Cel mai Nou→Cel mai Vechi" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Sortează după Nume A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Sortează după Nume Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Sortează după Mărime Cel mai Mic→Cel mai Mare" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Sortează după Mărime Cel mai Mare→Cel mai Mic" #: sabnzbd/skintext.py msgid "Uploading" msgstr "Încărcare" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "Forțează deconectarea" #: sabnzbd/skintext.py msgid "Removing job" msgstr "Elimin sarcina" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "Elimin sarcinile" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Precedent" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Următorul" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Goliţi Istoricul?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Trebuie să activaţi JavaScript pentru ca Plush să funcţioneze!" #: sabnzbd/skintext.py msgid "Options" msgstr "Opțiuni" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Pauză pentru câte minute?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Meniu Top" #: sabnzbd/skintext.py msgid "On Finish" msgstr "La Terminare" #: sabnzbd/skintext.py msgid "Sort" msgstr "Sortează" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Sortează după Vârstă (Cel mai Vechi→Cel mai Nou)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Sortează după Vârstă (Cel mai Nou→Cel mai Vechi)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Sortează după Nume (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Sortează după Nume (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Sortează după Mărime (Cel mai Mic→Cel mai Mare)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Sortează după Mărime (Cel mai Mare→Cel mai Mic)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Goliţi Coada?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Reîncerc toate sarcinile eșuate din Istoric?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Șterge" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Viteză Maximă" #: sabnzbd/skintext.py msgid "Range" msgstr "Interval" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Aplică la Selecţie" #: sabnzbd/skintext.py msgid "Everything" msgstr "Tot" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Rata de Reîmprospătare" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Lăţime Container" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "" "Acest lucru va preveni reîmprospătarea când cursorul mouse-ului este " "deasupra coadei." #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Blochează Reîmprospătarea Hover" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Încarcă" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Încarcă: .nzb .rar .zip .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Progres" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Spaţiul liber insuficient pe disc pentru finalizarea descărcărilor !" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Gol (Temp)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "INACTIV" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Descărcări" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Ştergere Finalizată" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Ştergeţi toate fişierele nereuşite din istoric?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Şterge Nereuşite" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Reîncearcă toate sarcinile eșuate?" #: sabnzbd/skintext.py msgid "Links" msgstr "Legături" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Afişare %s până la %s din totalul %s rezultate" #: sabnzbd/skintext.py msgid "No results" msgstr "Fără rezultate" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Afişăm un rezultat" #: sabnzbd/skintext.py msgid "First" msgstr "Primul" #: sabnzbd/skintext.py msgid "Last" msgstr "Ultimul" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "Email Trimis!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Notificare Trimisă!" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Salvăm.." #: sabnzbd/skintext.py msgid "Saved" msgstr "Salvat" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Comută Adaugă NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "VedereDuală1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "VedereDuală2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Sunteţi sigur că doriţi să reporniţi SABnzbd?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Ascunde Opţiuni Editare" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Arată Opţiuni Editare" #: sabnzbd/skintext.py msgid "Edit" msgstr "Editează" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Timp rămas" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "Vrăjitor Pornire-Rapidă SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "Versiune SABnzbd" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Precedent" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Detalii Server" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "" "Vă rugăm să introduceţi detaliile furnizorului dvs principal de usenet." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Numărul de conexiuni permis de furnizor" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "De ex. 8 sau 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Selectează doar dacă furnizorul dvs. permite conexiuni SSL." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Clic pentru a testa detaliile introduse." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "De ex." #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "Instalarea este acum completă!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd va rula acum în fundal." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "Închidere a oricărei ferestrele browser/file NU va închide SABnzbd." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Este recomandat să faceţi clic dreapta şi să faceţi o scurtatură , pe care " "să o folosiţi pentru a accesa SABnzbd când rulează în fundal." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Ajutor suplimentar poate fi găsit pe pagina noastră" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Du-te la SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Închide SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Porneşte Vrăjitor" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd vine cu ABSOLUT NICI O GARANŢIE.\n" "Acesta este software gratis, şi sunteţi binevenit să-l redistribuiţi în " "anumite condiţii.\n" "Este licenţiat sub GNU General Public License versiunea 2 sau (la opţiunea " "dumneavoastră) orice versiune ulterioară.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "Pentru a descărca de pe usenet veţi avea nevoie de un furnizor. ISP-ul dvs. " "vă poate oferi acces, totuşi un furnizor premium e recomandat." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "Nu aveţi un furnizor usenet? Vă recomandăm să încercaţi %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Eroare obţinere info TV (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Redenumire:%s în %s nereuşită" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Redenumire fişiere similare : %s în %s nereuşită" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Numele de server nu se rezolvă la DNS" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Acces neautorizat" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "Fișierul nu este pe server" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "URLGRABBER S-A BLOCAT" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Fişier NZB Inutilizabil" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "Descărcare URL nereuşită; %s" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "ATENŢIE: Sarcina \"%s\" întreruptă din cauza fişierelor RAR encriptate" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "Eroare CRC în %s (%s -> %s)" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "Dosarul \"%s\" nu există" #~ msgid "SQL Commit Failed, see log" #~ msgstr "Modificare SQL Nereuşită, vedeţi jurnal" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "" #~ "Nici un program UNRAR găsit, dezarhivarea fişierelor RAR imposibilă
" #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Versiunea dvs. UNRAR nu este recomandată, luaţi-o de la " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgid "Initiating restart...
" #~ msgstr "Iniţializare repornire...
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "Nici un program PAR2 găsit, repararea imposibilă
" #~ msgid "Error: No secondary interface defined." #~ msgstr "Eroare: Nici o interfaţă secundară definită." #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "Sarcina \"%s\" a fost re-adăugată în coadă" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Nu mă pot conecta la registru HKEY_CURRENT_USER." #~ msgid "Not matched" #~ msgstr "Nepotrivite" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "Sarcinile selectate cu '*' vor fi descărcate automat" #~ msgid "Downloaded so far" #~ msgstr "Decărcat până acum" #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Nu pot deschide cheie registru \"%s\"." #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Citire valoare registru pentru dosare speciale nereuşită" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd nu este compatibil cu unele programe firewall
\n" #~ " %s
\n" #~ " Ne pare rău, dar noi nu putem rezolva această incompatibilitate " #~ "acum.
\n" #~ " Vă rugăm să vă plângeţi producătorului dvs. de firewall.
\n" #~ "
\n" #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Este posibil că folosiţi ZoneAlarm în Vista.
" #~ msgid "OK" #~ msgstr "OK" #~ msgid "You have no permisson to use port %s" #~ msgstr "Nu ai permisiunea să foloseşti acest port %s" #~ msgid "Try again" #~ msgstr "Încercați din nou" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "modul pyopenssl lipsă, instalaţi-l pentru acces https" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Dezarhivare nereuşită, acest(e) fişier(e) sunt lipsă:" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "Dezarhivare nereuşită, un fişier aşteptat nu a fost dezarhivat" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Fişiere aşteptate lipsă: %s => eroare unrar?" #~ msgid "Main packet not found..." #~ msgstr "Pachet principal negăsit..." #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Eroare importare modul OpenSSL . Se conectează folosind NON-SSL" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Ştergere nzo din coadă post-procesare nereuşită (id)" #~ msgid "View script output" #~ msgstr "Vezi rezultat script" #~ msgid "Get NZB" #~ msgstr "Descarcă NZB" #~ msgid "KB/s" #~ msgstr "KB/s" #~ msgid "Queued" #~ msgstr "Pus în coadă" #~ msgid "Complete Dir" #~ msgstr "Dosar Complete" #~ msgid "Download speed" #~ msgstr "Viteză de descărcare" #~ msgid "WARNINGS" #~ msgstr "AVERTIZĂRI" #~ msgid " " #~ msgstr " " #~ msgid " or Report ID" #~ msgstr " sau Report ID" #~ msgid "Sort by name" #~ msgstr "Sortează după nume" #~ msgid "Sort by age" #~ msgstr "Sortează după vârstă" #~ msgid "Sort by size" #~ msgstr "Sortează după mărime" #~ msgid "Hide files" #~ msgstr "Ascunde fişiere" #~ msgid "Show files" #~ msgstr "Arată fişiere" #~ msgid "Remain/Total" #~ msgstr "Rămas/Total" #~ msgid "History Size" #~ msgstr "Mărime Istoric" #~ msgid "Delete all failed items from History?" #~ msgstr "Ştergeţi toate obiectele nereuşite din Istoric?" #~ msgid "Show Weblogging" #~ msgstr "Arată Jurnal Web" #~ msgid "Thread" #~ msgstr "Proces" #~ msgid "Email Test Result" #~ msgstr "Rezultat Test Email" #~ msgid "General configuration" #~ msgstr "Configuraţie Generală" #~ msgid "Secondary Web Interface" #~ msgstr "Interfaţă Web Secundară" #~ msgid "Web server authentication" #~ msgstr "Autentificare server web" #~ msgid "Activate an alternative skin." #~ msgstr "Activează o temă alternativă." #~ msgid "HTTPS Support" #~ msgstr "Suport HTTPS" #~ msgid "Queue auto refresh interval:" #~ msgstr "Interval reîmprospătare automată coadă:" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "" #~ "Interval reîmprospătare a coadei din pagina interfeţei web(sec, 0= niciunul)." #~ msgid "Disable API-key" #~ msgstr "Dezactivează cheie-API" #~ msgid "Folder configuration" #~ msgstr "Configurare Dosare" #~ msgid "Do not require the API key." #~ msgstr "Nu necesită cheie API." #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "UTILIZAŢI PE RISCUL DVS. !" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Director Script-uri Post-Procesare" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "Dosar ce conţine script-uri de post-procesare." #~ msgid "Enable built-in unrar functionality." #~ msgstr "Activează funcţionalitatea inclusă unrar." #~ msgid "Switches configuration" #~ msgstr "Configurare Comutatoare" #~ msgid "Enable Unrar" #~ msgstr "Activează Unrar" #~ msgid "Processing Switches" #~ msgstr "Comutatoare Procesare" #~ msgid "Enable Quick Check" #~ msgstr "Activează Verificare Rapidă" #~ msgid "Enable Filejoin" #~ msgstr "Activează Unire Fişiere" #~ msgid "Enable built-in unzip functionality." #~ msgstr "Activează funcţionalitatea inclusă unzip ." #~ msgid "Enable TS Joining" #~ msgstr "Activează Unire TS" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "" #~ "Uneşte fişierele care se termină în .001, .002 etc. într-un singur fişier." #~ msgid "Enable Par Cleanup" #~ msgstr "Activează Şterge Par" #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "" #~ "Uneşte fişierele care se termină în .001.ts, .002.ts etc. într-un singur " #~ "fişier." #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Nereuşit din cauza Erorilor CRC yEnc" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "" #~ "Când un articol are o eroare CRC , încearcă să-l iei de pe un alt server." #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Şterge fişierele par (dacă verificarea/repararea este cu succes)" #~ msgid "Default Priority" #~ msgstr "Prioritate Implicită" #~ msgid "Used when no user script is defined by the category." #~ msgstr "Folosit când nu este definit nici un script de categorie." #~ msgid "Default Post-Processing" #~ msgstr "Post-Procesare Implicită" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "Folosit când nu este definit nici o post-procesare de categorie." #~ msgid "Default User Script" #~ msgstr "Script Utilizator Implicit" #~ msgid "Enable MultiCore Par2" #~ msgstr "Activează Par2 MultiCore" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Folosit când nu este definit nici o prioritate de categorie." #~ msgid "Other Switches" #~ msgstr "Alte Comutatoare" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Înlocuieşte Caracterle Ilegale din Numele Dosarelor" #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Înlocuieşte caracterele ilegale din numele dosarelor cu echivalente (altfel " #~ "şterge)." #~ msgid "Do not download" #~ msgstr "Nu descărca" #~ msgid "SSL type" #~ msgstr "Tip SSL" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Folosiţi V23 doar dacă furnizorul dumneavoastră necesită altfel!" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Folosiţi sitemul 12 ore (AM/PM)" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Afişaţi timpii în notaţia AM/PM (nu afectează planificatorul)" #~ msgid "Server configuration" #~ msgstr "Configurare Server" #~ msgid "Server definition" #~ msgstr "Definiţie Server" #~ msgid "Scheduling configuration" #~ msgstr "Configurare Planificator" #~ msgid "Backup server" #~ msgstr "Server Secundar" #~ msgid "Click below to test." #~ msgstr "Clic mai jos pentru a testa." #~ msgid "Add Feed" #~ msgstr "Adaugă flux" #~ msgid "Delete Feed" #~ msgstr "Șterge flux" #~ msgid "RSS Configuration" #~ msgstr "Configurare RSS" #~ msgid "Remove" #~ msgstr "Șterge" #~ msgid "New Feed URL" #~ msgstr "Flux URL Nou" #~ msgid "Feeds" #~ msgstr "Fluxuri" #~ msgid "Skip" #~ msgstr "Omite" #~ msgid "Settings" #~ msgstr "Setări" #~ msgid "Email Options" #~ msgstr "Opţiuni Email" #~ msgid "User-defined categories" #~ msgstr "Categorii definite de utilizator" #~ msgid "Sorting configuration" #~ msgstr "Configurare Sortare" #~ msgid "Defines post-processing and storage." #~ msgstr "Defineşte post-procesarea şi stocarea." #~ msgid "Groups / Indexer tags" #~ msgstr "Grupuri / Taguri Indexer" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Permite sortarea şi redenumirea de episoade." #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Activează sortarea şi redenumirea generică a fişierelor." #~ msgid "Generic Sorting" #~ msgstr "Sortare Generică" #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Activează dacă descărcările nu sunt puse în dosarele lor." #~ msgid "Original Foldername" #~ msgstr "Nume de Dosar Original" #~ msgid "folder" #~ msgstr "dosar" #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Activează sortarea şi redenumirea fişierelor denumite după dată." #~ msgid "Are you sure you want to delete" #~ msgstr "Sigur doriți să ștergeți" #~ msgid "Page" #~ msgstr "Pagină" #~ msgid "Close" #~ msgstr "Închide" #~ msgid "Set Pause Interval" #~ msgstr "Setează Interval Pauză" #~ msgid "Pause Interval" #~ msgstr "Interval Pauză" #~ msgid "Pause for 24 hours" #~ msgstr "Pauză timp de 24 ore" #~ msgid "Pause for 12 hours" #~ msgstr "Pauză timp de 12 ore" #~ msgid "Left" #~ msgstr "Stânga" #~ msgid "Open Source URL" #~ msgstr "Deschide URL Sursă" #~ msgid "Storage" #~ msgstr "Stocare" #~ msgid "Plush Options" #~ msgstr "Opţiuni Plush" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Încarcă: .nzb .rar .zip .gz" #~ msgid "Hour:Min" #~ msgstr "Ore:Min" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Citeşte Flux va descărca conţinutul fluxului curent. " #~ "Descărcare Forţată va descărca toate NZB-urile " #~ "corespunzătoare acum." #~ msgid "Access" #~ msgstr "Acces" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Permite acces HTTPS la SABnzbd." #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Acces SABnzbd protejat cu parolă (recomandat)" #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Vreau SABnzbd să fie vizibilă numai de pe PC-ul meu." #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "" #~ "Vreau SABnzbd să fie vizibil de către orice calculator din reţeaua mea." #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "Lansează navigatorul meu web la pornirea SABnzbd ." #~ msgid "Misc" #~ msgstr "Diverse" #~ msgid "Please enter a whole number." #~ msgstr "Vă rugăm să introduceţi un număr întreg." #~ msgid "This field is required." #~ msgstr "Acest câmp este obligatoriu." #~ msgid "Step One" #~ msgstr "Pasul Unu" #~ msgid "Step Two" #~ msgstr "Pasul Doi" #~ msgid "Step Three" #~ msgstr "Pasul Trei" #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "După repornire SABnzbd ,îl veţi putea acesa la următoarea locaţie: %s" #~ msgid "Step Four" #~ msgstr "Pasul Patru" #~ msgid "Step Five" #~ msgstr "Pasul Cinci" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd are nevoie de un port tcp/ip liber pentru serverul său " #~ "intern.
\n" #~ " Portul %s de pe %s a fost încercat , dar contul folosit de SABnzbd nu " #~ "are permisiunea de a-l folosi.
\n" #~ " În sisteme OSX şi Linux , utilizatori normali trebuie să folosească " #~ "porturi peste 1023.
\n" #~ "
\n" #~ " Vă rugăm să reporniţi SABnzbd cu un număr de port diferit." #~ msgid "Add new downloads" #~ msgstr "Adaugă descărcări noi" #~ msgid "Purge Failed History" #~ msgstr "Goleşte Istoric Descărcări Nereuşite" #~ msgid "Email Account Settings" #~ msgstr "Setări Cont Email" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Ignoră verificarea par2 când fişierele sunt complete 100%%." #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "De ex. 119 sau 563 pentru SSL" #~ msgid "Filters" #~ msgstr "Filtre" #~ msgid "Check result of unpacking" #~ msgstr "Verifică rezultatul dezarhivării" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Verifică rezultatul dezarhivării ( trebuie să fie dezactivat pentru unele " #~ "sisteme de fișiere )" #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Fișier par2 invalid, nu pot verifica sau repara" #~ msgid "Only for optional servers" #~ msgstr "Doar pentru servere opționale" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Aplică numărul maxim de reîncercări la serverele opționale" #~ msgid "QR Code" #~ msgstr "Cod QR" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "" #~ "Activează clasă mesaje ce vor fi raportate (niciunul, unul sau mai multe)" #~ msgid "Notification classes" #~ msgstr "Clase notificări" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "" #~ "ATENŢIE: Sarcină \"%s\" abandonată deoarce conţine un fişier RAR ecriptat" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "Trimite în mod automat rezultatele validate de descărcare la index." #~ msgid "Automatic Feedback" #~ msgstr "Feedback Automat" #~ msgid "Site API Key" #~ msgstr "Cheie API Site" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Această cheie are rol de identificare la index. Informații suplimentare pe " #~ "https://www.oznzb.com/profile." #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Funcționalitate suplimentară inclusiv ratinguri și alte informații " #~ "suplimentare sunt disponibile dacă se conectează la indexul OZnzb." #~ msgid "Enable OZnzb Integration" #~ msgstr "Activează Integrarea OZnzb" #~ msgid "Refer to https://www.oznzb.com/profile" #~ msgstr "Vezi informații în https://www.oznzb.com/profile" #~ msgid "OZnzb" #~ msgstr "OZnzb" SABnzbd-2.3.2/po/main/ru.po0000644000000000000000000047720313217005051013466 0ustar 00000000000000msgid "" msgstr "" "Project-Id-Version: SABnzbd-0.7.x\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Pavel Maryanov \n" "Language-Team: Russian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:31+0000\n" "X-Generator: Launchpad (build 18511)\n" "Generated-By: pygettext.py 1.5\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Не удалось запустить веб-интерфейс" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "" "Не удаётся найти шаблон веб-интерфейса: %s. Выполняется попытка использовать " "стандартный шаблон" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "Модуль _yenc... НЕ найден" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "Исполняемый файл par2... НЕ найден" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "Исполняемый файл unrar... НЕ найден" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "Исполняемый файл unzip... НЕ найден" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Учтите, что для имени компьютера 0.0.0.0 потребуется IPv6-адрес для внешнего " "доступа" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "HTTPS отключён, поскольку отсутствуют файлы CERT и KEY" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "" #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Предупреждение" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "Завершение работы SABnzbd закончено" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Не задано имя компьютера." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "Подключения не настроены. Добавьте хотя бы одно подключение." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Пароль скрыт под ******. Повторите пароль." #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Недопустимые данные сервера" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "Тайм-аут. Попробуйте включить SSL или использовать другой порт." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Время ожидания истекло" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Недопустимый адрес сервера." #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Во время входа на сервер был выполнен выход." #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Для сервера требуется имя пользователя и пароль." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Подключение установлено!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Ошибка проверки подлинности. Проверьте имя и пароль." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "Слишком много подключений. Приостановите загрузку или повторите попытку позже" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Не удалось определить результат подключения (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Получен сигнал %s. Выполняется сохранение и выход..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Попытка загрузить NZB с %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Ошибка сохранения %s" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Не удаётся создать временный файл для %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Попытка установить статус для несуществующего сервера %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Ошибка в tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Ошибка загрузки %s" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Тестовое уведомление" #: sabnzbd/api.py msgid " Resolving address" msgstr " Разрешение адреса" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Ничего" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "по умолчанию" #: sabnzbd/api.py msgid "unknown" msgstr "неизвестно" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Не удалось составить регулярное выражение поиска: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "Приостановка из-за нехватки места на диске" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "На диске нет места Принудительная приостановка" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Ошибка диска при создании файла %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s отсутствует" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "" #: sabnzbd/assembler.py msgid "audio" msgstr "" #: sabnzbd/assembler.py msgid "spam" msgstr "" #: sabnzbd/assembler.py msgid "passworded" msgstr "" #: sabnzbd/assembler.py msgid "downvoted" msgstr "" #: sabnzbd/assembler.py msgid "keywords" msgstr "" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Квота исчерпана. Загрузка приостановлена" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s не является допустимым адресом электронной почты" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Требуется адрес сервера" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Не удаётся создать %s папку %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Не удаётся записать INI-файл %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Не удаётся создать файл резервной копии для %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Неправильно закодированный пароль %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s не является правильным восьмеричным значением" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "UNC-путь «%s» здесь не допускается" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "" #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Ошибка: очередь не пустая, папку нельзя изменить." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "Ошибка команды SQL (см. журнал)" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Не удалось закрыть базу данных (см. журнал)" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Недопустимый этап ведения журнала для %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Ошибка декодирования %s" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Неверно сформированная статья yEnc в %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Неизвестная ошибка декодирования %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => отсутствует на всех серверах, отброшен" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Завершено" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "Распаковка %s файлов или папок в %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "Не удаётся прочитать %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Не удалось добавить %s: удалён" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Ошибка удаления %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Не удаётся прочитать наблюдаемую папку %s" #: sabnzbd/downloader.py msgid "Resuming" msgstr "" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Приостановлено" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Сервер %s будет игнорироваться %s мин." #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Возможно, учётная запись используется где-то ещё" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Ошибка входа на сервер %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Не удаётся подключиться к серверу %s [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Для сервера %s требуется имя пользователя и пароль" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Завершение работы" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Не удалось подключиться к почтовому серверу" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "Не удалось установить TLS-соединение" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Ошибка входа на почтовый сервер" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Не удалось отправить электронное письмо" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Не удалось разорвать соединение с почтовым сервером" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "Электронное письмо успешно отправлено" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Не удаётся найти шаблонны электронных писем в %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Получатели не указаны. Электронное письмо не отправлено" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Недопустимая кодировка шаблона электронного письма %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Не найдены шаблоны электронных писем" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd: на диске нет места\n" "\n" "Привет.\n" "\n" "Система SABnzbd остановила загрузку, поскольку на диске почти не осталось " "свободного места.\n" "Освободите место на диске и возобновите работу SABnzbd вручную.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "" "Внимание! Имя LOCALHOST является неоднозначным. Используйте числовой IP-" "адрес." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Адрес сервера «%s:%s» является недопустимым." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Отсутствует ключ сеанса" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Ошибка: требуется ключ сеанса" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Ошибка: неправильный ключ сеанса" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "Отсутствует ключ API. Введите в сторонней программе ключ API из раздела " "«Настройка -> Общие»:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "Неправильный ключ API. Используйте в сторонней программе ключ API из раздела " "«Настройка -> Общие»:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Отсутствуют учётные данные. Введите в сторонней программе имя пользователя и " "пароль из раздела «Настройка -> Общие»:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
Система SABnzbd успешно остановлена.
Подождите 5 секунд и " "щёлкните ссылку ниже.

Обновить
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Лента" #: sabnzbd/interface.py msgid "Daily" msgstr "ежедневно" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "понедельник" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "вторник" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "среда" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "четверг" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "пятница" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "суббота" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "воскресенье" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "выкл." #: sabnzbd/interface.py msgid "Undefined server!" msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Неправильный параметр" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Назад" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "ОШИБКА" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Неправильное значение для %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "д" #: sabnzbd/misc.py msgid "h" msgstr "ч" #: sabnzbd/misc.py msgid "m" msgstr "м" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Не удаётся создать каталог %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "Каталог %s: ошибка доступа %s" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Не удалось создать (%s)" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Не удалось переместить %s в %s" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Не удалось создать ключ SSL и сертификат" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Не удаётся изменить права доступа %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Запуск сценария" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Пост-обработка была прервана (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Сценарий" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Объединение" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Неполная последовательность файлов, которые можно объединить" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Не удалось объединить файлы %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Ошибка объединения файлов: %s" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Ошибка «%s» выполнения file_join для %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] Объединено файлов: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Не удалось распаковать: %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Ошибка распаковки RAR-файлов: %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Ошибка «%s» выполнения rar_unpack для %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Не удалось удалить %s!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Попытка распаковки RAR-архива с паролем «%s»" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Ошибка распаковки: архив защищён паролем" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Распаковка" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Распаковать" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Ошибка распаковки: не удаётся найти %s" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "ОШИБКА: не удаётся найти «%s»" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Не удалось распаковать: ошибка CRC" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "ОШИБКА: неверная CRC-сумма для %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "Не удалось распаковать: ошибка записи или на диске нет места?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "ОШИБКА: не удалось записать (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Не удалось распаковать (см. журнал)" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "ОШИБКА: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s файлов в %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Ошибка «%s» выполнения unzip() для %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Быстрая проверка" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Исправить" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Быстрая проверка прошла успешно" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "запуск исправления" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Не удалось исправить: %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Ошибка %s выполнения par2_repair для набора %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Ошибка «%s» выполнения par2_repair для набора %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] Программе PAR2 переданы неправильные параметры. Проверьте параметры в " "разделе «Настройка -> Переключатели»" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Проверено за %s. Ошибок нет" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Проверено за %s. Требуется исправление" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "загрузка %s блоков..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Загрузка" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "" "Ошибка исправления: недостаточно блоков восстановления (не хватает %s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Исправление" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Исправлено за %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Проверка" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Проверка" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Вики-сайт" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Запуск/остановка" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "Добавлен NZB" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Запущена пост-обработка" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Задание завершено" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Другие сообщения" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Найден несовместимый файл очереди. Продолжение работы невозможно" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Ошибка загрузки %s: обнаружен повреждённый файл" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB-файл добавлен в очередь" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> неизвестная кодировка" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Файл %s пустой: пропущен" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Не удалось импортировать %s файлов из %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Неполный NZB-файл %s" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Недопустимый NZB-файл %s: пропущен (причина — %s, строка — %s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Пустой NZB-файл %s" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Пропущен повторяющийся NZB-файл «%s»" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Приостановлен повторяющийся NZB-файл «%s»" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "ПОВТОР" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "ЗАШИФРОВАН" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "СЛИШКОМ БОЛЬШОЙ" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "НЕПОЛНЫЙ" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "ОЖИДАНИЕ %s с" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Загружено за %s со средней скоростью %sБ/с" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Возраст" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s статей с ошибками" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s статей отсутствует" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s статей содержат несовпадающие повторы" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Ошибка импорта %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "предупреждений" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Бездействие" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Конфигурация" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Очередь" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Очистить очередь" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "История" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Очистить историю" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Ограничение скорости" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Приостановить" #: sabnzbd/osxmenu.py msgid "min." msgstr "мин." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Возобновить" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Сканировать наблюдаемую папку" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Полная папка" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Неполная папка" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Устранение неполадок" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Перезапустить" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Перезапустить без входа" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Выйти" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Первые 10 элементов очереди" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Пусто" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Последние 10 элементов истории" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Доступна новая версия" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Запустить мастер" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Остановка..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Проблема с" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " Службе SABnzbd требуется свободный порт TCP/IP для встроенного веб-" "сервера.
\n" " Был проверен порт %s на %s, но он оказался недоступен.
\n" " Возможно, этот порт используется другой программой, или служба SABnzbd " "уже запущена.
\n" "
\n" " Перезапустите службу SABnzbd, указав другой номер порта." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "" "Если снова появляется это сообщение об ошибке, попробуйте указать другой " "номер порта." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " Службе SABnzbd требуется действительный адрес сервера для встроенного " "веб-сервера.
\n" " Указан недействительный адрес.
\n" " Допустимые значения: localhost и 0.0.0.0
\n" "
\n" " Перезапустите службу SABnzbd, указав действительный адрес сервера." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " Обнаружены сохранённые данные из другой версии SABnzbd,
\n" " но данные другой программы нельзя повторно использовать.

\n" " Возможно, стоит сначала завершить очередь в другой программе.

\n" " После этого запустите данную программу с параметром «--clean».
\n" " При этом текущая очередь и журнал будут удалены!
\n" " Служба SABnzbd читает файл «%s»." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " Не удаётся найти файлы веб-интерфейса SABnbzd в %s.
\n" " Переустановите программу.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "Обнаружена критическая ошибка:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " Обнаружено, что отсутствует файл sqlite3.dll.

\n" " Этот файл мог быть удалён плохо настроенной антивирусной " "программой.
\n" " Попробуйте проверить параметры своей антивирусной программы, " "переустановите SABnzbd и сообщите о проблеме поставщику этого антивирусного " "ПО.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Нажмите клавиши STARTKEY+R и введите команду (пример):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Откройте окно командной сроки и введите команду (пример):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Программа не запустилась!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Критическая ошибка" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "Не удаётся запустить браузер. Возможно, он не было найден" #: sabnzbd/panic.py msgid "Access denied" msgstr "Доступ запрещён" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Ошибка %s: укажите действительное имя пользователя и пароль." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Отмена пост-обработка из-за ошибки проверки" #: sabnzbd/postproc.py msgid "Moving" msgstr "Перемещение" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "%s отправлено в очередь" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Ошибка переименования «%s» и «%s»" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Не удалось переместить файлы" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Запуск пользовательского сценария %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "Запущено %s" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Подробнее" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Ошибка пост-обработки для %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "см. журнал" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Не удалось загрузить" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Не удалось очистить %s." #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Не удалось удалить рабочий каталог (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Загрузка завершена" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Не удаётся создать конечную папку %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Пост-обработка" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Нет PAR2-файлов" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Проверка SFV-суммы" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Некоторые файлы не прошли проверку «%s»" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Проверка SFV-сумм прошла успешно" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Не удалось удалить %s" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Не удалось перевести систему в состояние гибернации" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Не удалось перевести систему в состояние сна" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Не удалось завершить работу системы" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Адрес сервера" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "Ключ API" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Неправильное описание RSS-ленты «%s»" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Не удалось получить RSS-ленту из %s: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Неправильные учётные данные для ленты %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "RSS-лента %s была пустой" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Несовместимая лента" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Обнаружена пустая запись RSS (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Показать интерфейс" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Выключить" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "осталось" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Добавить NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Недопустимое расписание %s в %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Неизвестное действие: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Расписание для несуществующего сервера %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Загрузить" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Объединить файлы" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Источник" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Серверы" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Сбой" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Ошибка" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "ожидание" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Исправление..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Извлечение..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Перемещение..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Запуск сценария..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Загрузка дополнительных блоков..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Быстрая проверка..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Проверка..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "загружается" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Частота" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Действие" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Аргументы" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Задача" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "отключить сервер" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "включить сервер" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Ограничить скорость" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Приостановить все" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Приостановить пост-обработку" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Возобновить пост-обработку" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Читать RSS-ленты" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Выкл." #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "обычный" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "высокий" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "низкий" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "МБ" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "ГБ" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "час" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "часов" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "мин" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "минут" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "с" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "секунд" #: sabnzbd/skintext.py msgid "day" msgstr "день" #: sabnzbd/skintext.py msgid "days" msgstr "дней" #: sabnzbd/skintext.py msgid "week" msgstr "неделя" #: sabnzbd/skintext.py msgid "Month" msgstr "Месяц" #: sabnzbd/skintext.py msgid "Year" msgstr "Год" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "День месяца" #: sabnzbd/skintext.py msgid "This week" msgstr "за эту неделю" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "за этот месяц" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "за сегодня" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "всего" #: sabnzbd/skintext.py msgid "on" msgstr "на" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "" #: sabnzbd/skintext.py msgid "Python Version" msgstr "" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Адрес" #: sabnzbd/skintext.py msgid "Comment" msgstr "" #: sabnzbd/skintext.py msgid "Send" msgstr "" #: sabnzbd/skintext.py msgid "Cancel" msgstr "" #: sabnzbd/skintext.py msgid "Other" msgstr "" #: sabnzbd/skintext.py msgid "Report" msgstr "" #: sabnzbd/skintext.py msgid "Video" msgstr "" #: sabnzbd/skintext.py msgid "Audio" msgstr "" #: sabnzbd/skintext.py msgid "Not used" msgstr "" #: sabnzbd/skintext.py msgid "or less" msgstr "" #: sabnzbd/skintext.py msgid "Log in" msgstr "" #: sabnzbd/skintext.py msgid "Log out" msgstr "" #: sabnzbd/skintext.py msgid "Remember me" msgstr "" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "Клиент автоматической загрузки из USENET" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Сохранить" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Уверены?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Удалить все загруженные файлы?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Главная" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Настройка" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Состояние" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Справка" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Форум" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Общие" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Папки" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Переключатели" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Расписание" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Уведомления" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "Эл. почта" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Категории" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Сортировка" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Особая" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Каталог загрузки" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "ПРИОСТАНОВЛЕНО" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "Статей в кэше: %s (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Загрузка системы" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Доступна новая версия %s на" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Остановить SABnzbd?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Добавить" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Добавить файл" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Категория" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Обработка" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Приоритет" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+исправить" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+распаковать" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+удалить" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "U" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "D" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "принудительный" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Остановить" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "Введите URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "По окончании очереди" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "выключить ПК" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "перевести ПК в режим ожидания" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "перевести ПК в спящий режим" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Закрыть SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Ограничение скорости" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Приостановить на" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Порядок" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Название" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "ост." #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "ВОЗРАСТ" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Удалить" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Повторить" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Действия" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Сценарии" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Удалить из очереди все элементы?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Удалить NZB" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Удалить NZB и стереть файлы" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Удалить NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Удалить NZB и стереть файлы" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "из" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Отсутствуют статьи" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Осталось квоты" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "вручную" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Сбросить квоту" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Удалить все завершённые элементы из истории?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Скрыть подробности" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Показать подробности" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Показать неудачные" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Показать все" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Размер" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Удалить неудачные NZB" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Удалить неудачные NZB и стереть файлы" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Удалить завершённые NZB" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "Дополнительный NZB (необязательно)" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Путь" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "" #: sabnzbd/skintext.py msgid "Other problem" msgstr "" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Принудительно отключить" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Отправка тестового письма на указанный почтовый ящик" #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Показать журнал" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Проверить электронную почту" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Журнал" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Ошибки и предупреждения" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ информация" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ отладка" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Соединения" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Последние предупреждения" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "Очистить" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Разблокировать" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Идентификатор статьи" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Набор файлов" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Время" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Тип" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Включен" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "" #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "" #: sabnzbd/skintext.py msgid "Config File" msgstr "Файл конфигурации" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Используемый кэш" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Эта кнопка перезапустит SABnzbd.
Используйте её, когда программа " "работает нестабильно.
Загрузка будет приостановлена до перезапуска и " "снова возобновлена после запуска." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" #: sabnzbd/skintext.py msgid "Advanced" msgstr "" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "В папке загрузки есть осиротевшие задания.
Их можно удалить (вместе с " "файлами) или поставить обратно в очередь." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "Эта кнопка перезапустит SABnzbd и полностью
перестроит содержимое " "очереди, не трогая уже загруженные файлы.
При этом порядок очереди " "будет изменён." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Изменения не были сохранены и будут потеряны." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Распаковывать ZIP" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" #: sabnzbd/skintext.py msgid "Version" msgstr "Версия" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Время работы" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Резервный" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Описание см. на вики-странице." #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Перезапуск SABnzbd..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Для применения изменений необходимо перезапустить SABnzbd!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "Веб-сервер SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "Сервер SABnzbd" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Адрес, по которому будет доступна служба SABnzbd." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "Порт SABnzbd" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Порт, по которому будет доступна служба SABnzbd." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Веб-интерфейс" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Выберите тему." #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "Имя пользователя SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Необязательное имя пользователя для входа." #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "Пароль SABnzbd" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Необязательный пароль для входа." #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "Включить HTTPS" #: sabnzbd/skintext.py msgid "not installed" msgstr "не установлено" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Доступ к интерфейсу по протоколу HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "Порт HTTPS" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Если не указать, будет доступен только стандартный порт с HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "Сертификат HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Название файла или путь к сертификату HTTPS." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "Ключ HTTPS" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Название файла или путь к ключу HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "" #: sabnzbd/skintext.py msgid "Tuning" msgstr "Тонкая настройка" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "Интервал опроса RSS-лент" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Интервал проверки (в минутах, не менее 15). Если используется планировщик, " "этот параметр не отключён." #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Ограничить кэш статей" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Кэширование статей в памяти для уменьшения количества обращений к диску.
В байтах, после числа можно добавить K, M или G. Пример: «64M» или " "«128M»" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Список очистки" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Сохранить изменения" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Сбросить" #: sabnzbd/skintext.py msgid "Language" msgstr "Язык" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Выберите язык веб-интерфейса." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "" "По этому ключу сторонние программы смогут получить полный доступ к SABnzbd." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "Ключ NZB" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "По этому ключу сторонние программы смогут загружать файлы в доступ к SABnzbd." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Создать новый ключ" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "QR-код ключа API" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" #: sabnzbd/skintext.py msgid "External internet access" msgstr "" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" #: sabnzbd/skintext.py msgid "No access" msgstr "" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "" #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "" #: sabnzbd/skintext.py msgid "Full API" msgstr "" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "ПРИМЕЧАНИЕ. Папки будут созданы автоматически при сохранении. Можно " "использовать абсолютные пути для сохранения за пределами папок по умолчанию." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Пользовательские папки" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "" #: sabnzbd/skintext.py msgid "In" msgstr "В" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Папка временной загрузки" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Место для хранения необработанных загрузок.
Изменить можно только " "тогда, когда очередь пуста." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Минимальное свободное место в папке временной загрузки" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Загрузка останавливается при уменьшении свободного места до этого " "значения.
В байтах, после числа можно добавить K, M, G или T. " "Пример: «800M» или «8G»" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Папка завершённых загрузок" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Место для сохранения готовых, полностью обработанных загрузок.
Можно " "переопределить в пользовательских категориях." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Права доступа для завершённых загрузок" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Шаблон прав доступа для завершенных файлов и/или папок.
В " "восьмеричном формате. Пример: «755» или «777»" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Наблюдаемая папка" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Папка для поиска NZB-файлов.
NZB-файлы также ищутся в архивах ZIP, " "RAR и TAR.GZ." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Частота сканирования наблюдаемой папки" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Число секунд между для поисками NZB-файлов." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Папка шаблонов электронных писем" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Папка, содержащая пользовательские шаблоны электронной почты." #: sabnzbd/skintext.py msgid "Password file" msgstr "Файл паролей" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Файл, содержащий все пароли, которые будут испробованы для зашифрованных RAR-" "файлов." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Системные папки" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Административная папка" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Место для хранения и базы данных очереди и журнала.
Изменить можно " "только тогда, когда очередь пуста." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "Данные не будут перемещены. Требуется перезапуск SABnzbd!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Папка журнала" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Место для хранения файлов журнала SABnzbd.
Требуется перезапуск " "SABnzbd!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr "Папка для хранения копий NZB" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Место, где будут сохраняться NZB-файлы" #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Базовая папка по умолчанию" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "" #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "" #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Загружать статьи только из начала очереди" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Включите, что уменьшить использование памяти. Отключите, чтобы медленные " "задания не блокировали очередь." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Обрабатывать только проверенные задания" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "Обрабатывать только задания, успешно прошедшие все проверки PAR2." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Обнаруживать повторяющиеся загрузки" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Отменить" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Использовать проверку по SFV" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Выполнять дополнительную проверку по SFV-файлам." #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "" #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Переименовывать папки" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Использовать временные названия при пост-обработке. Отключите, если ваша " "система обрабатывает это неправильно." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Пользовательский сценарий до помещения в очередь" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Используется до того, как NZB помещается в очередь." #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Дополнительные параметры PAR2" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Параметры Nice" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "Параметры IONice" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Отключаться, если очередь пуста" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "" "Отключаться от серверов Usenet, если очередь пуста или приостановлена." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Сортировать по возрасту" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Автоматически сортировать элементы по (среднему) возрасту" #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Проверять наличие обновлений" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Еженедельно проверять доступность новых версий SABnzbd." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Заменять пробелы в названиях папок" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Заменять пробелы на символы подчёркивания в названиях папок." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Заменять точки в названиях папок" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Заменять точки на пробелы в названиях папок." #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "" #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Открывать браузер при запуске" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Открывать веб-браузер по умолчанию при запуске SABnzbd." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Приостановить загрузку во время пост-обработки" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Приостановить загрузку с началом пост-обработки и возобновить по её " "окончании." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Игнорировать образцы" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Отфильтровывать файлы образцов (например, образцы видео)." #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Удалить после загрузки" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" #: sabnzbd/skintext.py msgid "Server" msgstr "Сервер" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Пост-обработка" #: sabnzbd/skintext.py msgid "Naming" msgstr "Именование" #: sabnzbd/skintext.py msgid "Quota" msgstr "Квота" #: sabnzbd/skintext.py msgid "Indexing" msgstr "" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Объем, который можно загрузить в месяц (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "День сброса трафика" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "День месяца или недели (1 — понедельник), когда провайдер сбрасывает квоту. " "(дополнительно можно указать чч:мм)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Автоматически возобновлять" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "Возобновлять загрузку после сброса квоты?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Период квоты" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "Сбрасывается ли квота каждый день, неделю или месяц?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Проверять перед загрузкой" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Попытаться спрогнозировать успешное завершение до фактической загрузки " "(медленнее!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Число попыток" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Максимальное число повторных попыток для каждого сервера" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "" #: sabnzbd/skintext.py msgid "Abort If" msgstr "" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "" #: sabnzbd/skintext.py msgid "Video rating" msgstr "" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "" #: sabnzbd/skintext.py msgid "Spam" msgstr "" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Добавить сервер" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Порт" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Имя пользователя" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Пароль" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Время ожидания" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Срок хранения" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "отключено" #: sabnzbd/skintext.py msgid "Minimal" msgstr "" #: sabnzbd/skintext.py msgid "Strict" msgstr "" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Дополнительный" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Включить" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Удалить сервер" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Проверить сервер" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Сбросить счётчики" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Данные проверки сервера..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Трафик" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Отправлять группу" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Отправлять команду группы перед запросом статей." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "" #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" #: sabnzbd/skintext.py msgid "Personal notes" msgstr "" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Добавить задание" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Текущие задания" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "Чтобы включить ленту и автоматически проверять обновление её содержимого, " "установите флажок напротив её названия.
После добавления ленты " "загружаться будут только новые её элементы, а не те, что были опубликованы " "раньше (если только на нажать кнопку «Загрузить принудительно»)." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Прочитать ленту" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Загрузить принудительно" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Фильтр" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Принять" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Отклонить" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Требуется" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "Требуется категория" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Соответствующие" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Нет соответствий" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Загружено" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Прочитать все ленты" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "Уведомление по электронной почте после завершения задания" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Никогда" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Всегда" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Только при ошибках" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Уведомления о нехватке места на диске" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "" "Отправлять электронное письмо, когда на диске нет места и загрузка SABnbzd " "приостановлена." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Отправлять RSS-уведомления" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "" "Отправлять электронное письмо, когда в очередь добавляется задание из RSS-" "ленты." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "Сервер SMTP" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Укажите сервер своего провайдера для исходящей почты." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "Получатель" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "Адрес электронной почты получателя уведомлений." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "Отправитель" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "От кого будут отправляться уведомления" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "НЕОБЯЗАТЕЛЬНОЕ имя пользователя" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "" "Имя пользователя учётной записи (для электронной почты с проверкой " "подлинности)." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "НЕОБЯЗАТЕЛЬНЫЙ пароль" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "" "Пароль учётной записи (для электронной почты с проверкой подлинности)." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Использовать Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Отправлять уведомления в Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Используется только для удалённого сервера Growl (адрес:порт)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Пароль сервера" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Необязательный пароль для сервера Growl" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "Использовать NotifyOSD" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Отправлять уведомления в NotifyOSD" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Если завершить путь звёздочкой (*), папки заданий не будут создаваться." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Относительный путь для папок" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Папка или путь" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Сортировка сериалов" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Использовать сортировку по ТВ-шоу" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Ключи шаблона" #: sabnzbd/skintext.py msgid "Clear" msgstr "Очистить" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "" #: sabnzbd/skintext.py msgid "Presets" msgstr "Готовые шаблоны" #: sabnzbd/skintext.py msgid "Example" msgstr "Пример" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Использовать сортировку по фильмам" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Хранить несвязанные загрузки в дополнительных папках" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Задействованные категории" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Значение" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Шаблон" #: sabnzbd/skintext.py msgid "Result" msgstr "Результат" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Сезон Папка" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Сезон Папка" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Эпизод Папка" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Эпизод Папка" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Название" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Название фильма" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Название.фильма" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Название_фильма" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Название сериала" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Название.сериала" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Название_сериала" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Номер сезона" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Номер эпизода" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Название эпизода" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Название.эпизода" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Название_эпизода" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Расширение файла" #: sabnzbd/skintext.py msgid "Extension" msgstr "Расширение" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Номер части" #: sabnzbd/skintext.py msgid "Decade" msgstr "Десятки" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Исходное название файла" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Нижний регистр" #: sabnzbd/skintext.py msgid "TEXT" msgstr "ТЕКСТ" #: sabnzbd/skintext.py msgid "text" msgstr "текст" #: sabnzbd/skintext.py msgid "file" msgstr "файл" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Строка сортировки" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Обозначение нескольких частей" #: sabnzbd/skintext.py msgid "In folders" msgstr "В папках" #: sabnzbd/skintext.py msgid "No folders" msgstr "Без папок" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Сортировка даты" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Использовать сортировку по дате" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Папка с названием сериала" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "Папки с годом и месяцем" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Папки по дням" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "case-adjusted" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Обработанный результат" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Редко используемые параметры. Их описание можно просмотреть на вики-" "странице, доступной по кнопке «Справка».
Не изменяйте эти параметры, не " "изучив сначала вики-страницу, поскольку их изменение может иметь серьезные " "последствия.
В скобках показаны значения по умолчанию." #: sabnzbd/skintext.py msgid "Values" msgstr "Значения" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Изменить данные NZB" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Удалить" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "В начало" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Вверх" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Вниз" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "В конец" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Все" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Обратить" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Название файла" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Тема" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Выбрать" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Приостановить на 5 минут" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Приостановить на 15 минут" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Приостановить на 30 минут" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Приостановить на 1 час" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Приостановить на 3 часа" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Приостановить на 6 часов" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "осталось" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "свободно на диске" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Пакетные операции" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "" #: sabnzbd/skintext.py msgid "Check all" msgstr "" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "" #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "ПРЕДУПРЕЖДЕНИЕ" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Загрузить" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Частота обновления" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "" #: sabnzbd/skintext.py msgid "History item limit" msgstr "" #: sabnzbd/skintext.py msgid "Date format" msgstr "" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "стр." #: sabnzbd/skintext.py msgid "Loading" msgstr "" #: sabnzbd/skintext.py msgid "articles" msgstr "" #: sabnzbd/skintext.py msgid "Rename" msgstr "Переименовать" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Исправление очереди" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Удалить всё" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Имя файла (необязательно)" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "" #: sabnzbd/skintext.py msgid "Submit" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Открыть URL с информацией" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Просмотреть журнал сценария" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Доступно обновление!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Другой" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Скорость" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Подтвердите удаление очереди" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Подтвердите удаление журнала" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Приостановить на..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Обновить" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Сортировать по возрасту от старых к новым" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Сортировать по возрасту от новых к старым" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Сортировать по названию от А до Я" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Сортировать по названию от Я до А" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Сортировать по размеру от мелких к крупным" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Сортировать по размеру от крупных к мелким" #: sabnzbd/skintext.py msgid "Uploading" msgstr "" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "" #: sabnzbd/skintext.py msgid "Removing job" msgstr "" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Предыдущая" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Следующая" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Удалить историю?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Для работы Plush необходимо включить JavaScript" #: sabnzbd/skintext.py msgid "Options" msgstr "Параметры" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "На сколько минут приостановить?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Верхнее меню" #: sabnzbd/skintext.py msgid "On Finish" msgstr "По завершении:" #: sabnzbd/skintext.py msgid "Sort" msgstr "Сортировка" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Сортировать по возрасту от старых к новым" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Сортировать по возрасту от новых к старым" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Сортировать по названию от А до Я" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Сортировать по названию от Я до А" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Сортировать по размеру от мелких к крупным" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Сортировать по размеру от крупных к мелким" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Очистить очередь?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "" #: sabnzbd/skintext.py msgid "Purge" msgstr "Удалить" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Макс. скорость" #: sabnzbd/skintext.py msgid "Range" msgstr "Диапазон" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Применить к выделенным" #: sabnzbd/skintext.py msgid "Everything" msgstr "все" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Частота обновления" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Ширина контейнера" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "" "Это позволит предотвратить обновление содержимого при наведении указателя " "мыши на очередь." #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Блокировать обновление при наведении мыши" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Отправить" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Ход выполнения" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Не хватает места на диске для завершения загрузки!" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "свободно (временно)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "БЕЗДЕЙСТВИЕ" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Загрузки" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Удаление завершено" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Удалить все неудачные элементы из истории?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Ошибка удаления" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "" #: sabnzbd/skintext.py msgid "Links" msgstr "Ссылки" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Показаны результаты с %s по %s из %s" #: sabnzbd/skintext.py msgid "No results" msgstr "Нет результатов" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Показан один результат" #: sabnzbd/skintext.py msgid "First" msgstr "Первая" #: sabnzbd/skintext.py msgid "Last" msgstr "Последняя" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "Сообщение отправлено" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Уведомление отправлено" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Сохранение..." #: sabnzbd/skintext.py msgid "Saved" msgstr "Сохранено" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Переключить добавление NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "ДвойнойВид1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "ДвойнойВид2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Перезапустить SABnzbd?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Скрыть параметры редактирования" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Показать параметры редактирования" #: sabnzbd/skintext.py msgid "Edit" msgstr "Изменить" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Осталось времени" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "Мастер быстрого запуска SABnzbd" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "Версия SABnzbd" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Назад" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Данные сервера" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Введите данные своего основного поставщика услуг Usenet." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Количество подключений, разрешённое провайдером" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "Например, 8 или 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Включайте, только если вашим провайдером разрешены SSL-соединения." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Нажмите, чтобы проверить введённые данные." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Например," #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "Настройка завершена." #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "Служба SABnzbd теперь будет выполняться в фоновом режиме." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "" "Если закрыть окна или вкладки браузера, служба SABnzbd НЕ будет остановлена." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Рекомендуется щёлкнуть страницу правой кнопкой мыши и добавить этот адрес в " "закладки, а затем использовать эту закладку для доступа к службе SABnzbd, " "работающей в фоновом режиме." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Дополнительные сведения доступны на нашем" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Перейти к SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd предоставляется БЕЗ КАКОЙ-ЛИБО ГАРАНТИИ.\n" "Это свободное программное обеспечение, и его можно распространять при " "соблюдении определённых условий.\n" "Она распространяется по лицензии GNU GENERAL PUBLIC LICENSE версии 2 или (по " "вашему выбору) любой более поздней версии.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "Для загрузки из сети Usenet требуется доступ к этой сети через " "соответствующего поставщика услуг. Ваш поставщик услуг Интернета может " "предоставить вам такой доступ, однако рекомендуется использовать usenet-" "провайдеров класса Premium." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "У вас ещё нет поставщика услуг Usenet? Рекомендуем попробовать %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Не удалось получить сведения о ТВ (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Не удалось переименовать: %s в %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Не удалось переименовать похожий файл: %s в %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Пустой NZB-файл" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "Не удалось загрузить URL: %s" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "ВНИМАНИЕ! Задание «%s» приостановлено из-за зашифрованного RAR-файла" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "Папка «%s» не существует" #~ msgid "SQL Commit Failed, see log" #~ msgstr "Ошибка фиксации SQL (см. журнал)" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "Ошибка CRC в %s (%s -> %s)" #~ msgid "Error: No secondary interface defined." #~ msgstr "Ошибка: дополнительный интерфейс не определён." #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Ваша версия UNRAR не рекомендуется к использованию. Загрузите подходящую " #~ "версию с сайта http://www.rarlab.com/rar_add.htm
" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "Программа UNRAR не найдена. Распаковка RAR-файлов невозможна
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "Программа PAR2 не найдена. Исправление файлов невозможно
" #~ msgid "Initiating restart...
" #~ msgstr "Инициирование перезапуска...
" #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "Задание «%s» было повторно добавлено в очередь" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "" #~ "Задания, помеченные звёздочкой (*), не будут загружаться автоматически." #~ msgid "Not matched" #~ msgstr "Не соответствующие" #~ msgid "Downloaded so far" #~ msgstr "Загружено на данный момент" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Не удаётся подключиться к кусту реестра HKEY_CURRENT_USER." #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Не удаётся открыть ключ реестра «%s»." #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Не удалось прочитать ключи реестра для специальных папок" #~ msgid "Try again" #~ msgstr "Повторить попытку" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "" #~ "Отсутствует модуль pyopenssl. Установите его для поддержки протокола HTTPS" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Отсутствует ожидаемый файл: %s => ошибка unrar?" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "Ошибка распаковки: ожидаемый файл не был распакован" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Ошибка распаковки: отсутствуют следующие файлы:" #~ msgid "Main packet not found..." #~ msgstr "Главный пакет не найден..." #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Недопустимые PAR2-файлы. Нельзя выполнить проверку или исправление" #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Ошибка импорта модуля OpenSSL. Подключение НЕ ЧЕРЕЗ SSL" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " Система SABnzbd несовместима с некоторыми программными " #~ "брандмауэрами.
\n" #~ " %s
\n" #~ " К сожалению эту несовместимость сейчас нельзя устранить.
\n" #~ " Отправьте жалобу поставщику своего брандмауэра.
\n" #~ "
\n" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " Службе SABnzbd требуется свободный порт TCP/IP для встроенного веб-" #~ "сервера.
\n" #~ " Был проверен порт %s на %s, но у учётной записи, используемой для " #~ "SABnzbd, нет прав для его использования.
\n" #~ " В системах OSX и Linux обычные пользователи должны использовать порты, " #~ "начиная с 1023.
\n" #~ "
\n" #~ " Перезапустите службу SABnzbd, указав другой номер порта." #~ msgid "OK" #~ msgstr "ОК" #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Скорее всего у вас используется ZoneAlarm для системы Vista.
" #~ msgid "You have no permisson to use port %s" #~ msgstr "У вас нет прав на использование порта %s" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Не удалось удалить NZO из очереди пост-обработки (id)" #~ msgid "View script output" #~ msgstr "Просмотреть выходные данные сценария" #~ msgid "Get NZB" #~ msgstr "Загрузить NZB" #~ msgid "KB/s" #~ msgstr "КБ/с" #~ msgid "Queued" #~ msgstr "В очереди" #~ msgid "Complete Dir" #~ msgstr "Каталог для завершённых" #~ msgid "Download speed" #~ msgstr "Скорость загрузки" #~ msgid "WARNINGS" #~ msgstr "ПРЕДУПРЕЖДЕНИЯ" #~ msgid "Add new downloads" #~ msgstr "Добавить новые загрузки" #~ msgid " " #~ msgstr " " #~ msgid " or Report ID" #~ msgstr " или код отчёта" #~ msgid "Sort by name" #~ msgstr "Сортировать по имени" #~ msgid "Sort by age" #~ msgstr "Сортировать по возрасту" #~ msgid "Sort by size" #~ msgstr "Сортировать по размеру" #~ msgid "Hide files" #~ msgstr "Скрыть файлы" #~ msgid "Show files" #~ msgstr "Показать файлы" #~ msgid "Remain/Total" #~ msgstr "Осталось/всего" #~ msgid "Purge Failed History" #~ msgstr "Очистить историю неудачных загрузок" #~ msgid "Delete all failed items from History?" #~ msgstr "Удалить все элементы с ошибками из истории?" #~ msgid "History Size" #~ msgstr "Размер истории" #~ msgid "Show Weblogging" #~ msgstr "Показать веб-журнал" #~ msgid "Thread" #~ msgstr "Поток" #~ msgid "Email Test Result" #~ msgstr "Результат проверки электронной почты" #~ msgid "General configuration" #~ msgstr "Общая конфигурация" #~ msgid "Secondary Web Interface" #~ msgstr "Дополнительный веб-интерфейс" #~ msgid "Activate an alternative skin." #~ msgstr "Активация дополнительной темы." #~ msgid "Web server authentication" #~ msgstr "Проверка подлинности веб-сервера" #~ msgid "HTTPS Support" #~ msgstr "Поддержка HTTPS" #~ msgid "Queue auto refresh interval:" #~ msgstr "Интервал автоматического обновления очереди:" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "" #~ "Интервал обновления веб-страницы очереди (в секундах, 0 — не обновлять)." #~ msgid "Disable API-key" #~ msgstr "Отключить ключ API" #~ msgid "Do not require the API key." #~ msgstr "Не требовать ключ API." #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "ИСПОЛЬЗУЙТЕ НА СВОЙ СТРАХ И РИСК!" #~ msgid "QR Code" #~ msgstr "QR-код" #~ msgid "Folder configuration" #~ msgstr "Настройка папок" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Папка сценариев пост-обработки" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "Папка, содержащая пользовательские скрипты для пост-обработки." #~ msgid "Switches configuration" #~ msgstr "Настройка переключателей" #~ msgid "Processing Switches" #~ msgstr "Обработка переключателей" #~ msgid "Enable Quick Check" #~ msgstr "Использовать быструю проверку" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Пропускать проверку PAR2, когда файлы на 100% корректные." #~ msgid "Enable Unrar" #~ msgstr "Распаковывать RAR" #~ msgid "Enable built-in unrar functionality." #~ msgstr "Включить встроенную функцию распаковки RAR-архивов." #~ msgid "Enable built-in unzip functionality." #~ msgstr "Включить встроенную функцию распаковки ZIP-архивов." #~ msgid "Enable Filejoin" #~ msgstr "Объединять файлы" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "Объединять файлы с расширениями 001, 002 и т. д. в один файл." #~ msgid "Enable TS Joining" #~ msgstr "Объединять TS" #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "Объединять файлы с расширениями 001.ts, 002.ts и т. д. в один файл." #~ msgid "Enable Par Cleanup" #~ msgstr "Удалять PAR" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Удалять PAR-файлы (в случае успешной проверки или исправления)." #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Сбой для CRC-ошибок yEnc" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "" #~ "Если статья содержит CRC-ошибку, попытаться загрузить её с другого сервера." #~ msgid "Check result of unpacking" #~ msgstr "Проверять результаты распаковки" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Проверять результаты распаковки (для некоторых файловых систем следует " #~ "отключить)." #~ msgid "Default Post-Processing" #~ msgstr "Пост-обработка по умолчанию" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "Используется, если пост-обработка не определена категорией." #~ msgid "Default User Script" #~ msgstr "Пользовательский сценарий по умолчанию" #~ msgid "Used when no user script is defined by the category." #~ msgstr "" #~ "Используется, если пользовательский сценарий не определен категорией." #~ msgid "Default Priority" #~ msgstr "Приоритет по умолчанию" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Используется, если приоритет не определён категорией." #~ msgid "Enable MultiCore Par2" #~ msgstr "Включить MultiCore PAR2" #~ msgid "Other Switches" #~ msgstr "Другие переключатели" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Заменять недопустимые символы в названиях папок" #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Заменять (или удалять) недопустимые символы на их эквиваленты в названиях " #~ "папок." #~ msgid "Do not download" #~ msgstr "Не загружать" #~ msgid "SSL type" #~ msgstr "Тип SSL" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Используйте V23, если только ваш провайдер не требует иного!" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Использовать 12-часовой формат (AM/PM)" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Отображать время в формате AM/PM (не влияет на планировщик)." #~ msgid "Only for optional servers" #~ msgstr "Только для дополнительных серверов" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "" #~ "Применять максимальное число повторных попыток только для дополнительных " #~ "серверов" #~ msgid "Server configuration" #~ msgstr "Конфигурация сервера" #~ msgid "Server definition" #~ msgstr "Определение сервера" #~ msgid "Backup server" #~ msgstr "Резервный сервер" #~ msgid "Click below to test." #~ msgstr "Нажмите кнопку внизу, чтобы начать проверку" #~ msgid "Scheduling configuration" #~ msgstr "Настройка расписания" #~ msgid "Remove" #~ msgstr "Удалить" #~ msgid "RSS Configuration" #~ msgstr "Настройка RSS" #~ msgid "New Feed URL" #~ msgstr "URL новой ленты" #~ msgid "Add Feed" #~ msgstr "Добавить ленту" #~ msgid "Delete Feed" #~ msgstr "Удалить ленту" #~ msgid "Skip" #~ msgstr "Пропустить" #~ msgid "Feeds" #~ msgstr "Ленты новостей" #~ msgid "Settings" #~ msgstr "Параметры" #~ msgid "Filters" #~ msgstr "Фильтры" #~ msgid "Email Options" #~ msgstr "Параметры электронной почты" #~ msgid "Email Account Settings" #~ msgstr "Параметры учётной записи электронной почты" #~ msgid "User-defined categories" #~ msgstr "Пользовательские категории" #~ msgid "Defines post-processing and storage." #~ msgstr "Категории определяют варианты пост-обработки и хранения." #~ msgid "Groups / Indexer tags" #~ msgstr "Группы / теги индексатора" #~ msgid "Sorting configuration" #~ msgstr "Настройка сортировки" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Позволяет сортировать и переименовывать эпизоды." #~ msgid "Generic Sorting" #~ msgstr "Обычная сортировка" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Позволяет сортировать и переименовывать файлы." #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Включите, если загрузки не размещаются в собственных папках." #~ msgid "Original Foldername" #~ msgstr "Исходное название папки" #~ msgid "folder" #~ msgstr "папка" #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Позволяет сортировать и переименовывать файлы с датой в названии." #~ msgid "Are you sure you want to delete" #~ msgstr "Действительно удалить" #~ msgid "Page" #~ msgstr "Страница" #~ msgid "Close" #~ msgstr "Закрыть" #~ msgid "Set Pause Interval" #~ msgstr "Задать интервал приостановки" #~ msgid "Pause Interval" #~ msgstr "Интервал приостановки" #~ msgid "Pause for 12 hours" #~ msgstr "Приостановить на 12 часов" #~ msgid "Pause for 24 hours" #~ msgstr "Приостановить на 24 часа" #~ msgid "Left" #~ msgstr "осталось" #~ msgid "Open Source URL" #~ msgstr "Открыть URL источника" #~ msgid "Storage" #~ msgstr "Хранилище" #~ msgid "Plush Options" #~ msgstr "Параметры Plush" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Допустимые расширения: NZB, RAR, ZIP и GZ" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Кнопка Прочитать ленту загрузит текущее содержимое ленты.. " #~ "Кнопка Загрузить принудительно загрузит все подходящие NZB-" #~ "файлы." #~ msgid "Hour:Min" #~ msgstr "Час:мин" #~ msgid "Access" #~ msgstr "Доступ" #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "Я хочу, чтобы SABnzbd был доступен всем компьютерам в моей сети." #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Я хочу, чтобы SABnzbd был доступен только моему компьютеру." #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Защита паролем доступа к SABnzbd (рекомендуется)" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Включить HTTPS-доступ к SABnzbd." #~ msgid "Misc" #~ msgstr "Разное" #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "Открывать веб-браузер со страницей SABnzbd при запуске программы." #~ msgid "This field is required." #~ msgstr "Это поле обязательно для заполнения." #~ msgid "Please enter a whole number." #~ msgstr "Введите целое число." #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "После перезапуска служба SABnzbd будет доступна по следующему адресу: %s" #~ msgid "Step One" #~ msgstr "Шаг первый" #~ msgid "Step Two" #~ msgstr "Шаг второй" #~ msgid "Step Three" #~ msgstr "Шаг третий" #~ msgid "Step Four" #~ msgstr "Шаг четвертый" #~ msgid "Step Five" #~ msgstr "Шаг пятый" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "Например, 119 или 563 для SSL" SABnzbd-2.3.2/po/main/SABnzbd.pot0000644000000000000000000030753113217004754014514 0ustar 00000000000000# # SABnzbd Translation Template file MAIN # Copyright 2011-2017 The SABnzbd-Team # team@sabnzbd.org # msgid "" msgstr "" "Project-Id-Version: SABnzbd-2.4.0-develop\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: shypike@sabnzbd.org\n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ASCII\n" "Content-Transfer-Encoding: 7bit\n" "POT-Creation-Date: 2017-12-06 10:56+W. Europe Standard Time\n" "Generated-By: pygettext.py 1.5\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "" #: SABnzbd.py [Warning message] msgid "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" #: SABnzbd.py [Warning message] msgid "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external access" msgstr "" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "" #: SABnzbd.py [Warning message] msgid "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems with Unicoded file and directory names in downloads." msgstr "" #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "" #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "" #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "" #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "" #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "" #: sabnzbd/utils/servertests.py msgid "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "" #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "" #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "" #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "" #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "" #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "" #: sabnzbd/api.py msgid " Resolving address" msgstr "" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "" #: sabnzbd/api.py msgid "unknown" msgstr "" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all passwords were tried)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all passwords were tried)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "" #: sabnzbd/assembler.py msgid "audio" msgstr "" #: sabnzbd/assembler.py msgid "spam" msgstr "" #: sabnzbd/assembler.py msgid "passworded" msgstr "" #: sabnzbd/assembler.py msgid "downvoted" msgstr "" #: sabnzbd/assembler.py msgid "keywords" msgstr "" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "" #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "" #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "Jobs will start unpacking during the downloading to reduce post-processing time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "" #: sabnzbd/downloader.py msgid "Resuming" msgstr "" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "" #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "" #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "" #: sabnzbd/interface.py msgid "API Key missing, please enter the api key from Config->General into your 3rd party program:" msgstr "" #: sabnzbd/interface.py msgid "API Key incorrect, Use the api key from Config->General in your 3rd party program:" msgstr "" #: sabnzbd/interface.py msgid "Authentication missing, please enter username/password from Config->General into your 3rd party program:" msgstr "" #: sabnzbd/interface.py [Warning message] msgid "Try our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin." msgstr "" #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid " 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "" #: sabnzbd/interface.py msgid "Daily" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "" #: sabnzbd/interface.py msgid "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "" #: sabnzbd/misc.py msgid "d" msgstr "" #: sabnzbd/misc.py msgid "h" msgstr "" #: sabnzbd/misc.py msgid "m" msgstr "" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "" #: sabnzbd/misc.py [Warning message] msgid "Your password file contains more than 30 passwords, testing all these passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate hostname mismatch: the server hostname is not listed in the certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "" #: sabnzbd/osxmenu.py msgid "min." msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "" #: sabnzbd/panic.py msgid "Problem with" msgstr "" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" #: sabnzbd/panic.py msgid "If you get this error message again, please try a different number.
" msgstr "" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.
\n" "
\n" msgstr "" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "" #: sabnzbd/panic.py msgid "Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "" #: sabnzbd/panic.py msgid "Access denied" msgstr "" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "Completed Download Folder %s is on FAT file system, limiting maximum file size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "Module subprocessww missing. Expect problems with Unicoded file and directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "" #: sabnzbd/postproc.py msgid "Moving" msgstr "" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "" #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "This key provides identity to indexer. Check your profile on the indexer's website." msgstr "" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "" #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "" #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "" #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "" #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "" #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "" #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "" #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "" #: sabnzbd/skintext.py msgid "day" msgstr "" #: sabnzbd/skintext.py msgid "days" msgstr "" #: sabnzbd/skintext.py msgid "week" msgstr "" #: sabnzbd/skintext.py msgid "Month" msgstr "" #: sabnzbd/skintext.py msgid "Year" msgstr "" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "" #: sabnzbd/skintext.py msgid "This week" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "" #: sabnzbd/skintext.py msgid "on" msgstr "" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "" #: sabnzbd/skintext.py msgid "Python Version" msgstr "" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "" #: sabnzbd/skintext.py msgid "Comment" msgstr "" #: sabnzbd/skintext.py msgid "Send" msgstr "" #: sabnzbd/skintext.py msgid "Cancel" msgstr "" #: sabnzbd/skintext.py msgid "Other" msgstr "" #: sabnzbd/skintext.py msgid "Report" msgstr "" #: sabnzbd/skintext.py msgid "Video" msgstr "" #: sabnzbd/skintext.py msgid "Audio" msgstr "" #: sabnzbd/skintext.py msgid "Not used" msgstr "" #: sabnzbd/skintext.py msgid "or less" msgstr "" #: sabnzbd/skintext.py msgid "Log in" msgstr "" #: sabnzbd/skintext.py msgid "Log out" msgstr "" #: sabnzbd/skintext.py msgid "Remember me" msgstr "" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "" #: sabnzbd/skintext.py msgid "Sysload" msgstr "" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "" #: sabnzbd/skintext.py msgid "Other problem" msgstr "" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "" #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "" #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "" #: sabnzbd/skintext.py msgid "Config File" msgstr "" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "" #: sabnzbd/skintext.py msgid "This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards." msgstr "" #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" #: sabnzbd/skintext.py msgid "Advanced" msgstr "" #: sabnzbd/skintext.py msgid "There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue." msgstr "" #: sabnzbd/skintext.py msgid "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "" #: sabnzbd/skintext.py msgid "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will be encrypted, however, validating a server's identity using its certificates is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-date local CA certificates are required." msgstr "" #: sabnzbd/skintext.py msgid "Speed up repairs by installing multicore Par2, it is available for many platforms." msgstr "" #: sabnzbd/skintext.py msgid "Version" msgstr "" #: sabnzbd/skintext.py msgid "Uptime" msgstr "" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "" #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "" #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "" #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "" #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "" #: sabnzbd/skintext.py msgid "If the SABnzbd Host or Port is exposed to the internet, your current settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "" #: sabnzbd/skintext.py msgid "not installed" msgstr "" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "" #: sabnzbd/skintext.py msgid "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "" #: sabnzbd/skintext.py msgid "Tuning" msgstr "" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "" #: sabnzbd/skintext.py msgid "Checking interval (in minutes, at least 15). Not active when you use the Scheduler!" msgstr "" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "" #: sabnzbd/skintext.py msgid "Cache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "" #: sabnzbd/skintext.py msgid "List of file extensions that should be deleted after download.
For example: nfo or nfo, sfv" msgstr "" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "Automatically delete completed jobs from History. Beware that Duplicate Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "" #: sabnzbd/skintext.py msgid "Language" msgstr "" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "" #: sabnzbd/skintext.py msgid "Help us translate SABnzbd in your language!
Add untranslated texts or improved existing translations here:" msgstr "" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "" #: sabnzbd/skintext.py msgid "NZB Key" msgstr "" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "" #: sabnzbd/skintext.py msgid "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" #: sabnzbd/skintext.py msgid "External internet access" msgstr "" #: sabnzbd/skintext.py msgid "You can set access rights for systems outside your local network. Requires List of local network ranges to be defined." msgstr "" #: sabnzbd/skintext.py msgid "No access" msgstr "" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "" #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "" #: sabnzbd/skintext.py msgid "Full API" msgstr "" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "" #: sabnzbd/skintext.py msgid "NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders." msgstr "" #: sabnzbd/skintext.py msgid "User Folders" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "" #: sabnzbd/skintext.py msgid "In" msgstr "" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "" #: sabnzbd/skintext.py msgid "Location to store unprocessed downloads.
Can only be changed when queue is empty." msgstr "" #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "" #: sabnzbd/skintext.py msgid "Auto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "" #: sabnzbd/skintext.py msgid "Location to store finished, fully processed downloads.
Can be overruled by user-defined categories." msgstr "" #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "" #: sabnzbd/skintext.py msgid "Set permissions pattern for completed files/folders.
In octal notation. For example: \"755\" or \"777\"" msgstr "" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files." msgstr "" #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "" #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "" #: sabnzbd/skintext.py msgid "Password file" msgstr "" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" #: sabnzbd/skintext.py msgid "System Folders" msgstr "" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "" #: sabnzbd/skintext.py msgid "Location for queue admin and history database.
Can only be changed when queue is empty." msgstr "" #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "" #: sabnzbd/skintext.py msgid "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr "" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "" #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "" #: sabnzbd/skintext.py msgid "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "" #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "" #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "" #: sabnzbd/skintext.py msgid "Enable for less memory usage. Disable to prevent slow jobs from blocking the queue." msgstr "" #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "" #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "" #: sabnzbd/skintext.py msgid "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "" #: sabnzbd/skintext.py msgid "Detect identical NZB files (based on items in your History or files in .nzb Backup Folder)" msgstr "" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "" #: sabnzbd/skintext.py msgid "Detect identical episodes in series (based on \"name/season/episode\" of items in your History)" msgstr "" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "" #: sabnzbd/skintext.py msgid "List all unwanted extensions. For example: exe or exe, com" msgstr "" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "" #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "" #: sabnzbd/skintext.py msgid "When the user script returns a non-zero exit code, the job will be flagged as failed." msgstr "" #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "" #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "When sorting, use tags from indexer for title, season, episode, etc. Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "" #: sabnzbd/skintext.py msgid "Use temporary names during post processing. Disable when your system doesn't handle that properly." msgstr "" #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "" #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "" #: sabnzbd/skintext.py msgid "Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay." msgstr "" #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "" #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "" #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "" #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "" #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "" #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "" #: sabnzbd/skintext.py msgid "Pauses downloading at the start of post processing and resumes when finished." msgstr "" #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "" #: sabnzbd/skintext.py msgid "Delete after download" msgstr "" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" #: sabnzbd/skintext.py msgid "Server" msgstr "" #: sabnzbd/skintext.py msgid "Post processing" msgstr "" #: sabnzbd/skintext.py msgid "Naming" msgstr "" #: sabnzbd/skintext.py msgid "Quota" msgstr "" #: sabnzbd/skintext.py msgid "Indexing" msgstr "" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "" #: sabnzbd/skintext.py msgid "On which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)" msgstr "" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "" #: sabnzbd/skintext.py msgid "Check before download" msgstr "" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "" #: sabnzbd/skintext.py msgid "When during download it becomes clear that too much data is missing, abort the job" msgstr "" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "" #: sabnzbd/skintext.py msgid "Indexers can supply rating information when a job is added and SABnzbd can report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "" #: sabnzbd/skintext.py msgid "Abort If" msgstr "" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "" #: sabnzbd/skintext.py msgid "Video rating" msgstr "" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "" #: sabnzbd/skintext.py msgid "Spam" msgstr "" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "Minimal: when SSL is enabled, verify the identity of the server using its certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "" #: sabnzbd/skintext.py msgid "Minimal" msgstr "" #: sabnzbd/skintext.py msgid "Strict" msgstr "" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "" #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "" #: sabnzbd/skintext.py msgid "Send Group" msgstr "" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "" #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "" #: sabnzbd/skintext.py msgid "None of the enabled servers have the 'Default' category selected. Jobs in the queue that are not assigned to one of the server's categories will not be downloaded." msgstr "" #: sabnzbd/skintext.py msgid "Personal notes" msgstr "" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "" #: sabnzbd/skintext.py msgid "The checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press \"Force Download\"." msgstr "" #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "" #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "" #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "" #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "" #: sabnzbd/skintext.py msgid "Email Sender" msgstr "" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "" #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "" #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "" #: sabnzbd/skintext.py msgid "Indexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to \"Indexer Categories / Groups\" to match more categories. Use commas to separate terms. Wildcards in the terms are supported.
More information can be found on the Wiki." msgstr "" #: sabnzbd/skintext.py msgid "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "" #: sabnzbd/skintext.py msgid "Clear" msgstr "" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "" #: sabnzbd/skintext.py msgid "Presets" msgstr "" #: sabnzbd/skintext.py msgid "Example" msgstr "" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "" #: sabnzbd/skintext.py msgid "Meaning" msgstr "" #: sabnzbd/skintext.py msgid "Pattern" msgstr "" #: sabnzbd/skintext.py msgid "Result" msgstr "" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "" #: sabnzbd/skintext.py msgid "Season Number" msgstr "" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "" #: sabnzbd/skintext.py msgid "File Extension" msgstr "" #: sabnzbd/skintext.py msgid "Extension" msgstr "" #: sabnzbd/skintext.py msgid "Part Number" msgstr "" #: sabnzbd/skintext.py msgid "Decade" msgstr "" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "" #: sabnzbd/skintext.py msgid "TEXT" msgstr "" #: sabnzbd/skintext.py msgid "text" msgstr "" #: sabnzbd/skintext.py msgid "file" msgstr "" #: sabnzbd/skintext.py msgid "Sort String" msgstr "" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "" #: sabnzbd/skintext.py msgid "In folders" msgstr "" #: sabnzbd/skintext.py msgid "No folders" msgstr "" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "" #: sabnzbd/skintext.py msgid "Rarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
Don't change these without checking the Wiki first, as some have serious side-effects.
The default values are between parentheses." msgstr "" #: sabnzbd/skintext.py msgid "Values" msgstr "" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "" #: sabnzbd/skintext.py msgid "Check all" msgstr "" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "" #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "" #: sabnzbd/skintext.py msgid "History item limit" msgstr "" #: sabnzbd/skintext.py msgid "Date format" msgstr "" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "" #: sabnzbd/skintext.py msgid "Loading" msgstr "" #: sabnzbd/skintext.py msgid "articles" msgstr "" #: sabnzbd/skintext.py msgid "Rename" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "" #: sabnzbd/skintext.py msgid "Submit" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "LocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!" msgstr "" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "" #: sabnzbd/skintext.py msgid "All usernames, passwords and API-keys are automatically removed from the log and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "" #: sabnzbd/skintext.py msgid "Uploading" msgstr "" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "" #: sabnzbd/skintext.py msgid "Removing job" msgstr "" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "" #: sabnzbd/skintext.py msgid "Options" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "" #: sabnzbd/skintext.py msgid "On Finish" msgstr "" #: sabnzbd/skintext.py msgid "Sort" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "" #: sabnzbd/skintext.py msgid "Purge" msgstr "" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "" #: sabnzbd/skintext.py msgid "Range" msgstr "" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "" #: sabnzbd/skintext.py msgid "Everything" msgstr "" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "" #: sabnzbd/skintext.py msgid "Container Width" msgstr "" #: sabnzbd/skintext.py msgid "This will prevent refreshing content when your mouse cursor is hovering over the queue." msgstr "" #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "" #: sabnzbd/skintext.py msgid "IDLE" msgstr "" #: sabnzbd/skintext.py msgid "Downloads" msgstr "" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "" #: sabnzbd/skintext.py msgid "Links" msgstr "" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "" #: sabnzbd/skintext.py msgid "No results" msgstr "" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "" #: sabnzbd/skintext.py msgid "First" msgstr "" #: sabnzbd/skintext.py msgid "Last" msgstr "" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "" #: sabnzbd/skintext.py msgid "Saving.." msgstr "" #: sabnzbd/skintext.py msgid "Saved" msgstr "" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "" #: sabnzbd/skintext.py msgid "DualView1" msgstr "" #: sabnzbd/skintext.py msgid "DualView2" msgstr "" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "" #: sabnzbd/skintext.py msgid "Edit" msgstr "" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "" #: sabnzbd/skintext.py msgid "Server Details" msgstr "" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "" #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "" #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "" #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "" #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "" #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "" #: sabnzbd/skintext.py [Wizard tip] msgid "It is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background." msgstr "" #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version.\n" msgstr "" #: sabnzbd/skintext.py msgid "In order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended." msgstr "" #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "" #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "" SABnzbd-2.3.2/po/main/sr.po0000644000000000000000000050104713217005051013456 0ustar 00000000000000# Serbian translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # ОZZII , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: ОZZII \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2015-12-28 10:25+0000\n" "Last-Translator: Safihre \n" "Language-Team: Serbian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:31+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Neuspešno pokretanje web interfejsa" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "Немогуће наћи веб модел: %s, програм покушава са стандардним моделом" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "_yenc modul... NIJE pronađen!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "par2 program...NIJE pronađen!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" "Verzija vašeg UNRAR-a je %s, mi preporučujemo verziju %s ili noviju.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "unrar program...NIJE pronađen!" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "unzip program...NIJE pronađen" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "7za program...NIJE pronađen" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Obratite pažnju, hostu 0.0.0.0 će trebati IPv6 adresa za pristup spolja" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "HTTP i HTTPS portovi ne mogu biti isti" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "HTTPS onemogućen zbog nedostajućih CERT i KEY datoteka" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Neuspešno pokretanje web interfejsa: " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "Nemoguće pristupiti SABHelper servisu" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s покренут" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Упозорење" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Грeшкa" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "Гашење SABnzbd је завршено" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Име хоста није унето." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "Везе нису подешене. Подесити макар једну везу." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Лозинка сакривена испод ******, поновите унос" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Погрешни детаљи сервера" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "" "Истекло време: Покушајте да упалите SSL или да се привежете на други порт." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Време је истекло" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Погрешна адреса сервера." #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Сервер се затворио при пријављивање" #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Серверу су потребни име и лозинка." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Успешно привезивање!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Аутентификација погрешна, проверити име/лозинку." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "Превише конекција, паузирајте преузимање или поновите касније" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Nemoguće odrediti rezultate konekcije (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Signal %s primljen, snimanje i napuštanje..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Fatalna greška pri snimanju trenutnog stanja" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Pokušaj da se učita NZB sa %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Snimanje %s neuspešno" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Nemoguće kreiranje privremene datoteke za %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Покушај постављања статуса за непостојећи сервер %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Грешка у tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Učitavanje %s neuspešno" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Učitavanje %s neuspešno sa greškom %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Probno obaveštenje" #: sabnzbd/api.py msgid " Resolving address" msgstr " Решавање адресе" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Ниједно" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Подразумевано" #: sabnzbd/api.py msgid "unknown" msgstr "непознато" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Neuspešna kompilacija regularne ekspresije za termin pretrage: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "Premalo prostora na disku, prisiljena PAUZA" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Disk je pun! Tera Pause" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Greška na disku prilikom kreiranja datoteke %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Fatalna greška u Assembler-u" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Prekinuto, detektovana enkripcija" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "UPOZORENJE: U \"%s\" pronađena neželjena ekstenzija u RAR datoteci. " "Neželjena datoteka je %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "Neželjena ekstenzija je u rar datoteci %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Prekinuto, detektovana neželjena ekstenzija" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "UPOZORENJE: Posao \"%s\" pauziran zbog ocene (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "UPOZORENJE: Posao \"%s\" prekinut zbog ocene (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Prekinuto, filter ocene se poklopio (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s nedostaje" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "video" #: sabnzbd/assembler.py msgid "audio" msgstr "аудио" #: sabnzbd/assembler.py msgid "spam" msgstr "neželjeno" #: sabnzbd/assembler.py msgid "passworded" msgstr "šifrovano" #: sabnzbd/assembler.py msgid "downvoted" msgstr "dole je glasao" #: sabnzbd/assembler.py msgid "keywords" msgstr "кључне речи" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Kvota utrošena, pauziram preuzimanja" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s nije ispravna email adresa" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Потребна је адреса сервера" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Не могу да креирам %s фасциклу %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Ne može da se upiše u INI datoteku %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Ne može se kreirati sigurnosna kopija za %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Pogrešno šifrovana lozinka %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s nije ispravna oktalna vrednost" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "UNC путања \"%s\" није дозвољена" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Greška: Dužina putanje bi trebala biti ispod %s" #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Грешка: ред није празан, фасцикла се не може променити." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "Не могу да пишем у бази дневника, проверите дозволе!" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "Baza dnevnika je oštećena, kreirana prazna zamena" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "Neuspešna SQL komanda, videti izveštaj" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Неуспешно затварање базе, видети извештај" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Погрешне етапе извештаја можете наћи у хронологији за %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Dešifrovanje %s neuspešno" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Лоше формиран yEnc артикал у %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Nepoznata greška pri dešifrovanju %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => фали на свим серверима, одбацивање" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Завршено" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "Издвојено %s датотека/фасцикла у %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "Неуспешно читање %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Грешка додавања %s, уклањање" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Greška pri uklanjanju %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Неуспешно читање надгледане фасцикле %s" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Nastavlja se" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Паузирано" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "" "Требате да поставите максимални проток пре него што поставите ограничење" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Server %s će biti ignorisan %s minuta" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Neuspešna inicijalizacija %s@%s iz razloga: %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "Previše konekcija ka serveru %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Moguće deljenje naloga" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Неуспешно пријављивање на сервер %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Neuspešno povezivanje na server %s[%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "Povezivanje na %s@%s neuspešno, poruka=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Server %s zahteva koriničko ime/lozinku" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Sumnja u grešku u programu za download" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Гашење" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Неуспешно привезивање на сервер е-поште" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "Неуспешна иницијализација TLS везе" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "Server nije pravilno odgovorio na helo pozdrav" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Неуспешна аутентификација на серверу е-поште" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Nije pronađen odgovarajući metod autentifikacije" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "Nepoznata greška pri autentifikaciji na email server" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Neuspešno slanje e-mail poruke" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Неуспешно затварање везе е-поште" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "Упешно слање е-поште" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Nemoguće poslati, nedostaju obavezni podaci" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Немогуће наћи модел е-поруке у %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Нема примаоце, е-порука није послана" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Погрешно енкодирање модела е-поруке %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Нема модела е-поруке" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "Za: %s\n" "Od: %s\n" "Datum: %s\n" "Tema: SABnzbd prijavljuje Disk Pun\n" "\n" "Zdravo,\n" "\n" "SABnzbd je stao sa downloadom zato što je disk skoro pun.\n" "Molimo Vas napravite mesta i pokrenite download u SABnzbd ručno.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "Пажња: LOCALHOST је двосмислен, користите ИП адресе." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Adresa servera \"%s:%s\" je neispravna" #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Недостаје кључ сесије" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Грешка: потребан је кључ сесије" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Грешка: Кључ сесије није добар" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "API кључ недостаје, унети у спољни програм API кључ из Подешавање->Опште:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "API кључ је погрешан, унети у спољни програм API кључ из Подешавања->Опште:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Недостаје аутентификација, унети у спољни програм име/лозинку из Подешавања-" ">Опште:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Isprobajte naš novi izgled Glitter! Svež, nov dizajn koji je optimizovan za " "desktop i mobilne uređaje. Idite na Podešavanja->Opšta da promenite izgled." #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "Б" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
Гашење SABnzbd-а је завршено.
Сачекајте око 5 секунди па " "кликните на линк испод.

Освежи
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Feed" #: sabnzbd/interface.py msgid "Daily" msgstr "Дневно" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "Понедељак" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Уторак" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Среда" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Четвртак" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Петак" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Субота" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Недеља" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "искљ." #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Server nije definisan!" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Погрешан параметар" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Назад" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "ГРЕШКА:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Погрешна вредност за %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "д" #: sabnzbd/misc.py msgid "h" msgstr "с" #: sabnzbd/misc.py msgid "m" msgstr "м" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Немогуће креирати фасциклу %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "Фасцикла %s: %s грешка приступа" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Neuspešno kreiranje (%s)" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Neuspešno premeštanje %s u %s" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Грешка креације SSL кључа и сертификата" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Не може да се промене дозволе од %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Покретање скрипта" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Пост-процесирање је заустављено (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Скрипт" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Previše ugnježdenih nivoa pri raspakivanju [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Спајање" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Непотпуна секвенца датотеке за спајање" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Спој датотеке %s није успело" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Грешка \"%s\" при споја датотеке" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Грешка \"%s\" док сам покренуо 'file_join' на %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] Спојено %s датотеке(а)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Neuspešno raspakivanje, %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Greška \"%s\" pri raspakivanju RAR datoteka" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Грешка \"%s\" док сам радио 'rar_unpack' на %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Neuspešno brisanje %s!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Proba raspakivanja sa lozinkom \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Neuspešno raspakivanje, arhiva zahteva lozinku" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Распакивање" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Распакуј" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Погрешно распакивање, не може да се нађе %s" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "ГРЕШКА: Не могу да нађем \"%s\"" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Neuspešno raspakivanje, CRC greška" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "ГРЕШКА: Погрешан CRC у \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "Neuspašno raspakivanje, greška u pisanju ili je disk pun?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "ГРЕШКА: грешка писања (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Neuspešno raspakivanje, putanja je predugačka" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "ГРЕШКА: путања је превелика (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Neuspešno raspakivanje, videti izveštaj" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "ГРЕШКА: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Neupotrebljiva RAR datoteka" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s датотека у %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Грешка \"%s\" при покретања 'unzip()' на %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Покушавам 7zip са лозинком \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "7ZIP скуп \"%s\" није потпун, не могу да издвојим" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Не могу да издвојим %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Брза Провера" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Поправи" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Брза Провера ОК" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Покретање пооправљања" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "Par provera neuspešna na %s, dok je QuickCheck uspešan!" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Neuspešna popravka, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Грешка %s при покретања 'par2_repair' на скупу %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Грешка \"%s\" при покретања 'par2_repair' на скупу %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] 'PAR2' је примио погрешне опције, проверите параметри Подешавање-" ">Прекидачи" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Проверено за %s, све датотеке су добре" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Проверено за %s, потребна је поправка" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "Учитавање %s блокова..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Добављам" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "Погрешна поправка, нема довољно блокова за поправку (фали %s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Поправљање" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Поправљено за %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Диск је пун" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Проверавање" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Провера" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Ovaj server ne dozvoljava SSL na ovom portu" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Вики" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Покретање/Гашење" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "НЗБ додат" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Пост-процесирање покренуто" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "посао завршен" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Неуспешан рад" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Ред завршен" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Остале поруке" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Недоступно" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Неуспешно слање Prowl поруке" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Neodgovarajući odgovor od strane Pushover (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Neuspešno slanje Pushover poruke" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Pogrešan odgovor Pushbullet-a (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Neuspešno slanje Pushbullet poruke" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "Стари ред је нађен, употребити Статус->Поправи за претварање реда" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Некомпатибилан ред нађен, на могу да наставим" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Грешка учитавање %s, покварена датотека нађена" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "Neuspešno ponovo pokretanje NZB nakon provere (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB додат у ред" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Непознато енкодирање" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Датотека %s је празна, прескакање" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Неуспешан унос %s датотеке са %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "Непотпуна НЗБ датотека %s" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Неважећи NZB %s, прескакање (разлог=%s, линија=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "Празан NZB %s" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Игнорисање дуплог NZB-а \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Паузирам због дуплог NZB-а \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Поништено, не може да се заврши" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "ДУПЛИКАТ" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "ШИФРИРАНО" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "ПРЕВЕЛИКО" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "НЕПОТПУНО" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "NEŽELJENI" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "FILTRIRANO" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "Чекање %s сек" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Преузето за %s на просек од %sБ/с" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Старост" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s артикла нису добро формирани" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s артикла недостају" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s артикла нису дупликате" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s артикла су уклоњени" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Грешка увоза %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Упозорења" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Мирoвање" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Поставке" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Ред" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Очисти ред" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Хронологија" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Очисти хронологију" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Ограничење брзине" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Пауза" #: sabnzbd/osxmenu.py msgid "min." msgstr "мин." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Настави" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Скенирај надгледану фасциклу" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Pročitani svi RSS kanali" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Комплетна фасцикла" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Некомплетна фасцикла" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Реши проблем" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Поново покрени" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Ponovno pokretanje bez prijave" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Излаз" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "У ред прве 10 ставке" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Празно" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Хронологија задњих 10 ставка" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Ново издање је доступно" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Покрени асистент" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Заустављам..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Проблем са" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd-у је потребан слободан tcp/ip порт за интерни веб сервер.
\n" " Покушан је порт %s на %s, али није доступан.
\n" " Неки други програм користи тај порт или SABnzbd већ ради.
\n" "
\n" " Поново покрените SABnzbd са другим портом." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "Ако опет имате ову грешку, покушајте други број.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd-у је потребна важећа хост адреса за интерни веб сервер.
\n" " Унели сте погрешну адресу.
\n" " Сигурне вредности су localhost и 0.0.0.0
\n" "
\n" " Поново покренути SABnzbd са добром хост адресом." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd је нашао сачуване податке неке друге верзије SABnzbd-а
\n" " али не може да искористи податке са другог програма.

\n" " Морате прво де завршите ред са другом верзијом програма.

\n" " После тога, покренути овај програм са опцијом \"--clean\".
\n" " То ће обрисати актуелни ред и хронилогију!
\n" " SABnzbd чита датотеку \"%s\"." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd не може да нађе датотеке веб интерфејса у %s.
\n" " Молимо да поново инстлирате програм.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd је нашао фаталну грешку:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd је нашао да недостаје датотека 'sqlite3.dll'.

\n" " Неки лоши против-вирусни програми уклањају ту датотеку.
\n" " Проверите против-вирусни програм, поново инсталирајте SABnzbd и " "пошаљите жалбу својим продавацу против-вируса.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Стиснути Startkey+R и унети линију (пример):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Отворите прозор терминала и унети линију (пример):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Програм није покренут!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Фатална грешка" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "Немогуће је покренути претраживач, вероватно није нађен" #: sabnzbd/panic.py msgid "Access denied" msgstr "Приступ одбијен" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Грешка %s: Требате да унесете важеће име/лозинку." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "Преузимање је можда погрешно. има %s од потребних %s" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Неуспешно преузимање - није на вашем серверу" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Нема пост-процесирање пошто провера није успела" #: sabnzbd/postproc.py msgid "Moving" msgstr "Премештање" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "%s послат у ред" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Грешка преименовања \"%s\" у \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Неуспешно премештање датотека" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Покретање скрипта %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "%s покренуто" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Kod prekida skripte je %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Више" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Грешка пост-процесирања за %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "видети извештај" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Неуспешно преузимање" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Чишћење %s није успело." #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Грешка у брисању радне фасцикле (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Преузимање завршено" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Немогуће креирање фасцикле %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Пост-процесирање" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Нема par2 датотеке" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Pokušaj SFV provere" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Неке датотеке нису проверене \"%s\"" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Успешна провера преко СФВ" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "Zahteva lozinku" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Brisanje %s neuspešno" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Неуспешна хибернација система" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Неуспено постављање система у стању приправности" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Greška pri gašenju sistema" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "Indekser id (%s) nije pronađen za datoteku ocenjivanja" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Адреса сервера" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "API кључ" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Погрешан опис RSS фида \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Неуспешно преузимање RSS од %s: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Немам важећу аутентификацију за фид %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "Greška na strani servera (kod greške %s); nemoguće dobiti %s na %s" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "Server %s koristi nepouzdan HTTPS sertifikat" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "RSS фид %s је празан" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Некомпатибилан Фид" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Nađen prazan RSS unos (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Pokaži interfejs" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Otvori fasciklu završenih" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Угаси" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Преостало" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Додај NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Лоша планификација %s у %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Непозната акција: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Планификација за непостојећи сервер %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Преузми" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Прилепити датотеке" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Извор" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Сервери" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Грешка" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Неуспешно" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "Чекам" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Popravljanje..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Распакујем..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Премештање..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Покретање скипта..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Преузимање екстра блокова..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Брза провера..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Проверавање..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Преузимам" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Фреквенција" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Акција" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Аргументи" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Задатак" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "Onemogući server" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "Omogući server" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Ограничење брзине" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Паузирај све" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Паузирај пост-процесирање" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Настави пост-процесирање" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Читај RSS фидове" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Уклони неуспешна посла" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Ukloni završene poslove" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Pauziraj poslove sa niskim prioritetom" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Pauziraj poslove sa normalnim prioritetom" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Pauziraj poslove sa visokim prioritetom" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Настави радови са ниским приоритетом" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Настави радови са нормалним приоритетом" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Настави радови са високим приоритетом" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Омогући управљање квота" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Онемогући управљање квота" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Искључено" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Врло ниско" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Умерено" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Нормалан" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Висок" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Хитно" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Низак" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "МБ" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "ГБ" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "сат" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "сата(и)" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "мин." #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "мин." #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "сек." #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "секунди(е)" #: sabnzbd/skintext.py msgid "day" msgstr "дан" #: sabnzbd/skintext.py msgid "days" msgstr "дана" #: sabnzbd/skintext.py msgid "week" msgstr "седмица" #: sabnzbd/skintext.py msgid "Month" msgstr "Месец" #: sabnzbd/skintext.py msgid "Year" msgstr "Година" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Дан у месецу" #: sabnzbd/skintext.py msgid "This week" msgstr "Ове седмице" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Овог месеца" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "Данас" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Укупно" #: sabnzbd/skintext.py msgid "on" msgstr "укљ." #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parametri" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Верзија Python-а" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Почетна страница" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "или" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Хост" #: sabnzbd/skintext.py msgid "Comment" msgstr "Komentar" #: sabnzbd/skintext.py msgid "Send" msgstr "Пошаљи" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Откажи" #: sabnzbd/skintext.py msgid "Other" msgstr "Остало" #: sabnzbd/skintext.py msgid "Report" msgstr "Izveštaj" #: sabnzbd/skintext.py msgid "Video" msgstr "Видео" #: sabnzbd/skintext.py msgid "Audio" msgstr "Аудио" #: sabnzbd/skintext.py msgid "Not used" msgstr "Није коришћено" #: sabnzbd/skintext.py msgid "or less" msgstr "ili manje" #: sabnzbd/skintext.py msgid "Log in" msgstr "" #: sabnzbd/skintext.py msgid "Log out" msgstr "" #: sabnzbd/skintext.py msgid "Remember me" msgstr "" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "Alatka za automatizovano preuzimanje sa usenet-a" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Сачувај" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Да ли сте сигурни?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Обриши све преузете датотеке?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Кућа" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Подешавање" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Статус" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Помоћ" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Форум" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "ИРЦ" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Опште" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Фасцикле" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Прекидачи" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Планирање" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Обавештења" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "Е-пошта" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Категорије" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Сортирање" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Посебно" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Претрага" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Фасцикла преузимања" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "ПАУЗИРАНО" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "Кеширано %s артикла (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Sysload" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Новије издање %s је доступно на" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Da li ste sigurni da želite ugasiti SABnzbd?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Додај" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Додај датотеку" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Категорија" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Обрађивање" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Приоритет" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Поправи" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Издвој" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Обриши" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "П" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "С" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "П" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Форсирај" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Заустави" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "Унесите УРЛ" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "Када се ред заврши" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Угаси рачунар" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "У стање приправности" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Хибернација" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Угаси SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Ограничење брзине" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Паузирај за" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Редослед" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Име" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "Процењено време" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "СТАРОСТ" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Обриши" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Покушај опет" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Акције" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Скрипте" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Обрисати све ставке са реда?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Очисти NZB" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Очисти NZB и обриши датотеке" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Ponovo pokušaj sve neuspešne poslove" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Уклони NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Уклони NZB и обриши датотеке" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "од" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Недостају артикли" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Остала квота" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "ручно" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Ресетуј квоту" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Обриши све завршене ставке са хронологије?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Сакриј детаље" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Прикажи детаље" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Прикажи погрешне" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Прикажи све" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Величина" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Очисти NZB са грешком" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Очисти NZB са грешком и обриши датотеке" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Очисти завршене NZB" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "Додатне опције NZB-а" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Путања" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Ponovo pokušaj sve neuspešne" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Ponovo pokušaj sve" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus/neželjeno" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "Van retencije" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Neki drugi problem" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Натерај искључење" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "То ће послати пробну е-поруку Вашем малогу." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Покажи извештај" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Пробна е-порука" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Бележење" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Грешке/Упозорења" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ Инфо" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ Дебаг" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Везе" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Најновија Упозорења" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "очисти" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Деблокирај" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Идентифација артикла" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Збир датотека" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "Када" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Тип" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Омогућено" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Управљачка табла" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Veza neuspešna!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Lokalna IPv4 adresa" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Javna IPv4 adresa" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "IPv6 adresa" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Nameserver/DNS Pretraga" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "Модел процесора" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "Performanse sistema (Pystone)" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Brzina foldera za preuzimanje" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Brzina foldera za kompletirana preuzimanja" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Brzina pisanja" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "Ne mogu da zapišem. Proverite da li je u fasciklu moguće pisati." #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Kliknite na dugme Ponovi test ispod, da odredite" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Ponovi test" #: sabnzbd/skintext.py msgid "Config File" msgstr "; Датотека подешавања" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "; Кеш" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Ово поново покреће SABnzbd.
Користити ако мислите да програм има " "проблем стабилности.
Преузимање ће бити паузирано и наставиће се после." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" #: sabnzbd/skintext.py msgid "Advanced" msgstr "" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Постоје усамљени радови у фасцикли преузимања.
Можете да их обришете " "(укључујући датотеке) или да их поново пошаљете у ред." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "То поново покреће SABnzbd и ради пуну
реконструкцију садржаја реда, " "чувајући већ преузете датотеке.
То мења ред реда." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Промене су изгубљене јер нису сачуване." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Omogući Unzip" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "Омогући 7zip" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" #: sabnzbd/skintext.py msgid "Version" msgstr "; Верзија" #: sabnzbd/skintext.py msgid "Uptime" msgstr "; Ради" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Резервно" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "За више информација, читајте Вики!" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Поновно покретање SABnzbd-а..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "За апликацију промена, поново покренути програм!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "SABnzbd Веб сервер" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "SABnzbd хост" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Хост на којем SABnzbd слуша." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "SABnzbd Порт" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Порт на који SABnzbd чека везе." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Веб интерфејс" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Odaberi izgled" #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "Корисничко име SABnzbd-а" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Корисничко име за аутентификацију (опционо)" #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "Лозинка SABnzbd-а" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Лозинка за аутентификацију (опционо)" #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "Активирај HTTPS" #: sabnzbd/skintext.py msgid "not installed" msgstr "никје инсталирано" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Приступ интерфејсу преко HTTPS адресе." #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "HTTPS порт" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Ако је празно, стандардни порт ће слушати само HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "HTTPS сертификат" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Датотека или путања до HTTPS сертификата." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "HTTPS кључ" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Датотека или путања до HTTPS кључа." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "HTTPS Chain цертификати" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Датотека или путања до HTTPS Chain" #: sabnzbd/skintext.py msgid "Tuning" msgstr "Штеловање" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "Интервал RSS провере" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Интервал провере (у минутима, макар 15). Неактивно када користите планер!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Макс брзина линије" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Постатак брзине линије" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "Који постотак брзине линије SABnzbd треба да користи, нпр. 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Лимит кеша артикла" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Кеширати артикле у меморији. То смањује приступ диска.
У бајтовима, " "опционо додати K,M,G. Пример: \"64M\" или \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Списак чишћења" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Листа ектензије за брисање после преузимања.
На пример: nfo или " "nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Сачувај промене" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Ресетуј" #: sabnzbd/skintext.py msgid "Language" msgstr "Језик" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Језик веб интерфејса" #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "Овај кључ допушта пун приступ SABnzbd-а другим програмима." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "NZB кључ" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "Кључ допушта да други програми додају NZB у SABnzbd." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Генериши нов кључ" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "QR Код АПИ кључа" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Lista lokalnih mrežnih raspona" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Sve lokalne mrežne adrese počinju sa sledećim prefiksima (najčešće " "\"192.168.1.\")" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Екстерни приступ интернету" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" #: sabnzbd/skintext.py msgid "No access" msgstr "Без приступа" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Dodaj NZB datoteke " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (без подешавања)" #: sabnzbd/skintext.py msgid "Full API" msgstr "Цео API" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Цео веб интерфејс" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "БЕЛЕШКА: Фасцикле ће бити аутоматски креиране приликом Сачувавања. " "Могуће је коришћење апсолутне путање за сачувавање ван подразумеваних " "фасцикли." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Корисничке фасцикле" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Pregledaj" #: sabnzbd/skintext.py msgid "In" msgstr "У" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Привремена фасцикла преузимања" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Смештај непроцесираних преузимања.
Промене су могуће само када је " "ред празан." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Минимални простор за привремену фасциклу" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Паузирај када је простор испод ове вредност.
У бајтовима, опционо " "додати K,М,G,T. НПР: \"800M\" или \"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Фасцикла за завршена преузимања" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Смештај завршених, процесираних преузимања.
Може се заобићи у " "дефинисаним категоријама." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Дозволе за фасциклу завршених преузимања" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Поставља дозволе за завршене датотеке/фасцикле.
У октал. На пример: " "\"755\" или \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Надгледана фасцикла" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Фасцикла за надгледање .nzb датотека.
Такође скенира " ".zip .rar и .tar.gz архиве у потрази за .nzb " "датотекама." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Интервал скенирања" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Број секунди између 2 провере .nzb датотека" #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Фасцикла модела е-поште" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Фасцикла где се налазе модели е-поште." #: sabnzbd/skintext.py msgid "Password file" msgstr "Лозинка датотеке" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "Датотека са свим лозинкама за шифроване РАР датотеке." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Системске фасцикле" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Фасцикла Администратора" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Локацију за ред и хронологију базе.
Промене су могуће само када је " "ред празан." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "" "Податци неће бити премештени. Потребно поновно покретање SABnzbd-" "а!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Фасцикла извештаја" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Смештај извештаја SABnzbd-а.
Потребно је поновно покретање SABnzbd-" "а!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr "Фасцикла копије .нзб" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Смештај за сачувавање .нзб датотека." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Подразумевана основна фасцикла" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Преузми све par2 датотеке" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Омогући рекурсивни издвој" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Издвој архиве (rar, zip, 7z) унутра архиве." #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Ignoriši foldere unutar arhiva" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Sve datoteke će biti smeštene u jedan folder" #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Само артикли на врху реда" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Упали за мању употребу меморије. Угасити ради спречавања блокирања реда " "спорим радовима." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Пост-процесирај само проверени послови" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "" "Огранићи пост-процесирање само за радове који су прешли све PAR2 провере." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Акција када је шифрован РАР преузет" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "Ако је \"Пауза\", требате да поставите лозинку и да наставите рад." #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Откриј дупликатна преузимања" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Откриј дупле епизоде у серије" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Одбаци" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Прекини" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Radnja kada je otkrivena neželjena ekstenzija" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "Radnja kada je otkrivena neželjena ekstenzija u RAR datotekama" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Neželjene ekstenzije" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Lista svih neželjenih ekstenzija. Na primer: exe or exe, com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Упали SFV провере" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Уради још једну проверу базирану на SFV датотеке." #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Korisničke skripte mogu uznačiti posao kao neuspešan" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "Kada korisnička skripta vrati kod koji nije nula, posao će biti označen kao " "neuspešan" #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "U slučaju neuspeha, pokušaj sa alternativnim NZB-om" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "Neki serveri nude alternativni NZB pri neuspešnom preuzimanju" #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Упали преименовање фасцикле" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Користи привремено име при пост-процесирање. Угасити уколико га Ваш систем " "то не прихвата како треба." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Кориснички скрипт пре-реда" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Коришћено пре него што NZB уђе у ред." #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Додатни параметри PAR2" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Параметри 'Nice'" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "Параметри 'IONice'" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Заустави везу када је ред празан" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "Искључи се са сервера када је ред празан или паузиран." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Сортирај по старост" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Аутоматско сортирај ставке по старост (просек)." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Провери нове верзије" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Недељно проверавај за новије верзије програма." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "И пробне верзије" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Размени размаке у имену фасцикле" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Размени размаке са _ у имену фасцикле." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Размени тачке у имену фасцикле" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Размени тачке са размацима у имену фасцикле." #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Napravi Windows kompatibilnim" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "Za servere: osiguraj da su imena kompatibilna sa Windows-om." #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Покрени претраживач при покретању" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Покрени Веб претраживач при покретању SABnzbd-а." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Паузирај док се пост-процесира" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "Паузирај преузимања на почетку пост-процесирања и настави после." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Игнориши примере" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Филтрирај примерне датотеке (нпр. видео пример)." #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Обриши после преузимања" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" #: sabnzbd/skintext.py msgid "Server" msgstr "Сервер" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Накнадна обрада" #: sabnzbd/skintext.py msgid "Naming" msgstr "Именовање" #: sabnzbd/skintext.py msgid "Quota" msgstr "Квота" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Индексирање" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Колико може да се преузме овог месеца (К/М/Г)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Дан ресетовања" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "Који дан месеца или недеље (1=понедељак) Ваш провајдер ресетује квоту? " "(опционо са hh:mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Automatski nastavi" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "Да се настави преузимање после ресета квоте?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Период квоте" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "Квота је ресетована сваки дан, недеље или месец?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Провери пре преузимања" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Покуша да предвиди успешан завршетак пре стварног преузимања (спорије!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Макс покушаја" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Макс покушаја по серверу" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Поништи рад који не може да се заврши" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Када током преузимања постаје јасно да превише података недостаје, прекинути " "посао" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Omogući filtriranje" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Radnje pri preuzimanju prema pravilima filtriranja." #: sabnzbd/skintext.py msgid "Abort If" msgstr "Obustavi ako" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Inače pauziraj ako" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Ocena videa" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Ocena zvuka" #: sabnzbd/skintext.py msgid "Spam" msgstr "Непожељна" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Potvrđeno" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Više negativnih nego pozitivnih" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Ključne reči naziva" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Lista razdvojena zarezom" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Balansiranje opterećenja servera" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Onemogući balansiranje opterećenja" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Omogući balansiranje opterećenja" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Omogući balansiranje opterećenja sa optimizacijom za IPv6" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "Korisno ukoliko news server ima više od jedne IPv4/IPv6 adrese" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Додај сервер" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Opis servera" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Порт" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Корисничко име" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Лозинка" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Време истекло" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Време задржавања" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "ССЛ" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Онемогућено" #: sabnzbd/skintext.py msgid "Minimal" msgstr "" #: sabnzbd/skintext.py msgid "Strict" msgstr "" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 je najveći prioritet, 100 je najniži prioritet" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Опционо" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Омогући" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Уклони сервер" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Пробај сервер" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Испразни бројаче" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Пробам детаље сервера..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Проток" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Пошаљи 'Group'" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Послати команду 'group' пре тражења артикла." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Koristi ovaj server samo za sledeće kategorije" #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Lične zabeleške" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Dodaj raspored" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "trenutni rasporedi" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "Кутијица поред имена фида треба да буде одабрана да би фид био омогућен и да " " провери нове ставке.
Када је фид додат, ће узети нове ставке а не оне " "које су већ у RSS фиду осим ако стиснете \"Натерај преузимање\"." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Читај фид" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Натерај преузимање" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Филтер" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Прихвати" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Одбаци" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Захтеви" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "ПотребанCat" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Najmanje" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Највише" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "Od SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Одговара" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Не одговара" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Преузето" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Сада читај све фидове" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "Нотификација е-поштом при завршетку рада" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Никад" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Увек" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Само-Грешке" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Обавештење пуног диска" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "Пошаљи е-поруку када је диск пун и SABnzbd паузиран." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Пошаљи RSS нотификације" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "Пошаљи е-поруку када RSS фид дода рад у ред." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "СМТП сервер" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Унети сервер излазних е-поруке вашег провајдера." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "Е-пошта примаоца" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "Адреса на коју се шаље е-порука." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "Е-пошта слања" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Е-пошта одакле долази нотификација" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "Корисничко име (ОПЦИОНО)" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Ако је потребна аутентификација за слање е-поште, унети име." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "Лозинка (ОПЦИОНО)" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Ако је потребна аутентификација за слање е-поште, унети лозинку." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Упали „Growl“" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Пошаљи обавештења у „Growl“" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Користи само удаљен „Growl“ сервер (хост:порт)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Лозинка сервера" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Опциона лозинка за „Growl“ сервер" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "Упали „NotifyOSD“" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Шаљи обавештења у „NotifyOSD“" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Центар за обавештења" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Пошаљи нотификације у Центру нотификације" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Windows notifikacije" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Windows notifikacije" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Омогући Prowl нотификације" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Потребан Prowl налог" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "API кључ за Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Лични API кључ за Prowl (потребно)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Omogući Pushover notifikacije" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Zahteva Pushover nalog" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Token aplikacije" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Token aplikacije (obavezan)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Korisnički ključ" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Korisnički ključ (obavezan)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Uređaj(i)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Uređaj(i) na koje bi poruke trebale biti poslate" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Omogući Pushbullet notifikacije" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Zahteva Pushbullet nalog" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Lični API ključ" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Vaš lični Pushbullet API ključ (obavezan)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Уређај" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Uređaj na koji bi poruka trebala biti poslata" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Завршавање путање са звездицом * ће спречити креацију фасцикле за рад." #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Релативност фасцикле је базирано" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Фасцикла/Путања" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Сортирање серије" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Упали сортирање ТВ-а" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Модел кључа" #: sabnzbd/skintext.py msgid "Clear" msgstr "Очисти" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "" #: sabnzbd/skintext.py msgid "Presets" msgstr "Предподешавања" #: sabnzbd/skintext.py msgid "Example" msgstr "Примери" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Упали сортирање филма" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Задржи изгубљена преузимања у фасциклама" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Погођене категорије" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Значење" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Модел" #: sabnzbd/skintext.py msgid "Result" msgstr "Резултат" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Фасцикла сезоне" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Фасцикла сезоне" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Фасцикла епизоде" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Фасцикла епизоде" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Наслов" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Име филма" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Име.Филма" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Име_филма" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Име серије" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Име.серије" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Име_Серије" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Број сезоне" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Број епизоде" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Име епизоде" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Име.Епизоде" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Име_епизоде" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Екстензија датотеке" #: sabnzbd/skintext.py msgid "Extension" msgstr "Екстензија" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Број дела" #: sabnzbd/skintext.py msgid "Decade" msgstr "Декада" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Оригинално име датотеке" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Мала слова" #: sabnzbd/skintext.py msgid "TEXT" msgstr "ТЕКСТ" #: sabnzbd/skintext.py msgid "text" msgstr "текст" #: sabnzbd/skintext.py msgid "file" msgstr "датотека" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Уреди низ" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Етикете више-партија" #: sabnzbd/skintext.py msgid "In folders" msgstr "У фасциклама" #: sabnzbd/skintext.py msgid "No folders" msgstr "Нема фасцикле" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Сређивање датумом" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Упали сређивање по датуму" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Фасцикла Име Серије" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "Фасцикле Година-Месец" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Дневне фасцикле" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "Прилагођено-слово" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Резултат обрађивања" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Опције ретко коришћене. За њихово значење и објашњење, клинути на дугме " "Помоћ за одлазак на Вики страницу.
Немојте их мењати пре не провере на " "Вики, пошто неке имају озбиљне нежељене ефекате.
Подразумеване вредности " "су између заграда." #: sabnzbd/skintext.py msgid "Values" msgstr "Вредности" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Уреди детаље NZB-а" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Обриши" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Врх" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Горе" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Доле" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Дно" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Све" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Окрени" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Име датотеке" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Тема" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Избор" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Паузирај 5 минута" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Паузирај 15 минута" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Паузирај 30 минута" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Паузирај 1 сат" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Паузирај 3 сата" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Паузирај 6 сати" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "остало" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Слободан простор" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Привремено" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Мулти-операције" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Držite taster shift pritisnut da bi ste odabrali raspon" #: sabnzbd/skintext.py msgid "Check all" msgstr "Proveri sve" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Ponovo pokreni SABnzbd" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Opcije statusa i interfejsa" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Ili prevucite i pustite datoteke u prozor!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Izgubljena konekcija sa SABnzbd" #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "" "U slučaju ponovnog pokretanja SABnzbd-a ovaj prozor će nestati automatski!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "ПАЖЊА:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Преузми" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Брзина освежавања" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Koristi globalna podešavanja interfejsa" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Limit stavku u redu" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Limit stavki u istoriji" #: sabnzbd/skintext.py msgid "Date format" msgstr "Формат датума" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Ekstra kolona reda" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "страни" #: sabnzbd/skintext.py msgid "Loading" msgstr "Учитавам" #: sabnzbd/skintext.py msgid "articles" msgstr "artikli" #: sabnzbd/skintext.py msgid "Rename" msgstr "Преименуј" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Поправљење реда" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Prikaži aktivne konekcije" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Zapušteni poslovi" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Pošalji nazad u red" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Избриши све" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Ponovo pokušaj sve" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Povuci NZB sa URL" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "Pošalji NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Опционо специфирати име" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Formati: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Пошаљи" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Отвори информативни УРЛ" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Poslato. Hvala!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Mišta nije odabrano!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Ukloni sve odabrane fajlove" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Sakrij/prikaži sve završene datoteke" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Види извештај скрипта" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Нова верзија доступна!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Прилагођено" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Брзина" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Потврда брисања реда" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Потврда брисања хронологије" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Koliko dugo ili dokle želite da pauzirate? (na engleskom!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Žao nam je, nismo mogli to da interpretiramo. Pokušajte ponovo." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Паузирај за..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Освежи" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Среди по старост Старије→Новије" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Среди по старост Новије→Старије" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Среди по имену A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Среди по имену Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Среди по величини Мање→Веће" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Среди по величини Веће→Мање" #: sabnzbd/skintext.py msgid "Uploading" msgstr "" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "" #: sabnzbd/skintext.py msgid "Removing job" msgstr "" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Претходно" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Следеће" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Очисти хронологију?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "За функционисање Plush-а упалите JavaScript!" #: sabnzbd/skintext.py msgid "Options" msgstr "Опције" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Паузирати за колико минута?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Главни мени" #: sabnzbd/skintext.py msgid "On Finish" msgstr "На крају" #: sabnzbd/skintext.py msgid "Sort" msgstr "Сортирај" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Среди по старост (Старије→Новије)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Среди по старост (Новије→Старије)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Среди по Имену (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Среди по Имену (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Среди по величини (Мање→Веће)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Среди по величини (Веће→Мање)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Очисти ред?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Pokušaj ponovo sve poslove u istoriji?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Очисти" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Највећа брзина" #: sabnzbd/skintext.py msgid "Range" msgstr "Опсег" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Примени на одабрано" #: sabnzbd/skintext.py msgid "Everything" msgstr "Све" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Освежавање" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Ширина контејнера" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "При прелазу миша преко рада, зауставља се обнова садржаја." #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Блокирати обнове на прелаз миша" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Слање" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Pošalji: .nzb .rar .zip .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Напредак" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Недовољно простора на диску за завршавање преузимања!" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Слободно (Привремено)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "ЧЕКА" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Преузимања" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Обриши завршено" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Обрисати све погрешне ставке са хронологије?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Obriši neuspešne" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Ponovo pokušati sve neuspešne poslove?" #: sabnzbd/skintext.py msgid "Links" msgstr "Линкови" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Приказивање %s до %s од %s резултата" #: sabnzbd/skintext.py msgid "No results" msgstr "Нема резултата" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Приказ једног резултата" #: sabnzbd/skintext.py msgid "First" msgstr "Прво" #: sabnzbd/skintext.py msgid "Last" msgstr "Последње" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "Е-порука је послата!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Обавештење послато!" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Snimanje..." #: sabnzbd/skintext.py msgid "Saved" msgstr "Сачувано" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Пребаци Додај NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "DualView1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "DualView2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Сигурно поново покренути SABnzbd?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Сакриј опције Уређивања" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Прикажи опције Уређивања" #: sabnzbd/skintext.py msgid "Edit" msgstr "Уреди" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Преостало време" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "Асистент брзог-покретања SABnzbd-а" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "Верзија SABnzbd-а" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Претходно" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Детаљи сервера" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Овде унети детаље вашег примарног 'usenet' провајдера." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Број веза дозвољене од стране провајдера" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "Нпр 8 или 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Одабрати САМО ако Ваш провајдер допушта SSL везе." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Кликнути за пробу унетих детаља." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "Нпр." #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "Подешавање је сада завршено!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd ће сада радити у позадини." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "Затварање прозора/језичка претраживаче НЕЋЕ затворити SABnzbd." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Препоручено је да поставите ову локацију као 'маркер' тако да Вам је приступ " "SABnzbd омогућен док он ради у позадини." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Даља помоћ се може наћи на" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Иди на SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Затвори SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Покрени чаробњака" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd долази БЕЗ ИКАКВЕ ГАРАНЦИЈЕ.\n" "Ово је бесплатан програм, и ви сте добродошли да га делите под одређеним " "условима.\n" "Лиценциран је под GNU GENERAL PUBLIC LICENSE верзија 2 или (по вашем избору) " "касније верзије.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "За преузимање са 'usenet' треба Вам приступ привајдеру. Можда Вам Ваш ISP " "пружа приступ, било како премијум провајдер је препоручен." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "Немате 'usenet' провајдер? Препоручујемо Вам %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Грешка преузимању ТВ инфо (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Неуспешно преименовање : %s у %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Неуспешно преименовање сличне датотеке: %s у %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Ime servera se ne može odrediti" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Neautorizovan pristup" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "URLGRABBER SE SRUŠIO" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "NZB датотека неупотребљива" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "Погрешно учитавање УРЛ-а; %s" #~ msgid "Step One" #~ msgstr "Корак 1" #~ msgid "Step Two" #~ msgstr "Корак 2" #~ msgid "Step Three" #~ msgstr "Корак 3" #~ msgid "Step Four" #~ msgstr "Корак 4" #~ msgid "Step Five" #~ msgstr "Корак 5" #~ msgid "Please enter a whole number." #~ msgstr "Молимо да унесете цео број." #~ msgid "This field is required." #~ msgstr "Ово поље је обавезно." #~ msgid "Access" #~ msgstr "Приступ" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Упали HTTPS приступ на SABnzbd." #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Заштити лозинком приступ SABnzbd-а (препоручено)" #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Желим да SABnzbd буде видљив само са мог рачунара." #~ msgid "Misc" #~ msgstr "Остало" #~ msgid "Hour:Min" #~ msgstr "Сат:Мин" #~ msgid "Open Source URL" #~ msgstr "Отвори изворни УРЛ" #~ msgid "Storage" #~ msgstr "Складиште" #~ msgid "Plush Options" #~ msgstr "Опције Plush" #~ msgid "Pause for 12 hours" #~ msgstr "Паузирај 12 сати" #~ msgid "Pause for 24 hours" #~ msgstr "Паузирај 24 сата" #~ msgid "Pause Interval" #~ msgstr "Интервал паузе" #~ msgid "Page" #~ msgstr "Лист" #~ msgid "Close" #~ msgstr "Затвори" #~ msgid "Set Pause Interval" #~ msgstr "Постави интервал паузе" #~ msgid "Are you sure you want to delete" #~ msgstr "Заиста избрисати" #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Упали сређивање и преименовање датотеке са датумом" #~ msgid "folder" #~ msgstr "фасцикла" #~ msgid "Original Foldername" #~ msgstr "Оригинално име фасцикле" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Упали генерално сортирање/преименовање датотеке." #~ msgid "Generic Sorting" #~ msgstr "Генеричко сортирање" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Упали сортирање/преименовање еписоде." #~ msgid "Sorting configuration" #~ msgstr "Подешавање сортирања" #~ msgid "Groups / Indexer tags" #~ msgstr "Групе/Индексуј ознаке" #~ msgid "Defines post-processing and storage." #~ msgstr "Дефиниши после-процесирање и стовариште." #~ msgid "User-defined categories" #~ msgstr "Корисничке категорије" #~ msgid "Email Account Settings" #~ msgstr "Поставке е-поште" #~ msgid "Feeds" #~ msgstr "Фидови" #~ msgid "Settings" #~ msgstr "Поставке" #~ msgid "Email Options" #~ msgstr "Опције е-поште" #~ msgid "Add Feed" #~ msgstr "Додај фид" #~ msgid "Skip" #~ msgstr "Прескочи" #~ msgid "Delete Feed" #~ msgstr "Обриши фид" #~ msgid "Scheduling configuration" #~ msgstr "Подешавање планификације" #~ msgid "Click below to test." #~ msgstr "Кликнути испод за пробу." #~ msgid "RSS Configuration" #~ msgstr "Подешавање RSS-а" #~ msgid "Remove" #~ msgstr "Уклони" #~ msgid "New Feed URL" #~ msgstr "УРЛ новог фида" #~ msgid "Backup server" #~ msgstr "Резервни сервер" #~ msgid "Server definition" #~ msgstr "Дефиниција сервера" #~ msgid "Server configuration" #~ msgstr "Подешавање сервера" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Покажи време у AM/PM (не утиче на планер)." #~ msgid "Do not download" #~ msgstr "Не преузимај" #~ msgid "SSL type" #~ msgstr "Тип ССЛ-а" #~ msgid "Enable MultiCore Par2" #~ msgstr "Упали 'MultiCore Par2'" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Коришћено када категорија не дефинише приоритет." #~ msgid "Other Switches" #~ msgstr "Остали прекидачи" #~ msgid "Default Priority" #~ msgstr "Подразумеван приоритет" #~ msgid "Used when no user script is defined by the category." #~ msgstr "Коришћено када категорија не дефинише скрипт." #~ msgid "Default Post-Processing" #~ msgstr "Подразумевано пост-процесирање" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "Употребљено када категорија не дефинише пост-процесирање." #~ msgid "Default User Script" #~ msgstr "Подразумеван скрипт" #~ msgid "Enable Filejoin" #~ msgstr "Упали склапање" #~ msgid "Enable TS Joining" #~ msgstr "Упали TS склапање" #~ msgid "Enable Par Cleanup" #~ msgstr "Упали чишћење Пар-а" #~ msgid "Switches configuration" #~ msgstr "Подешавање прекидача" #~ msgid "Processing Switches" #~ msgstr "Опције обраде" #~ msgid "Enable Quick Check" #~ msgstr "Упали брзу проверу" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Фасцикла пост-процесирања" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "Фасцикла која садржи скиптове за пост-процесирање" #~ msgid "Folder configuration" #~ msgstr "Подешавања фасцикле" #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "Користите на сопствену одговорност!" #~ msgid "Queue auto refresh interval:" #~ msgstr "Интервал обнове реда:" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "Интервал обнове реда у веб интерфејсу (у секундама, 0=без)." #~ msgid "HTTPS Support" #~ msgstr "HTTPS подршка" #~ msgid "Web server authentication" #~ msgstr "Аутентификација веб сервера" #~ msgid "General configuration" #~ msgstr "Општа подешавања" #~ msgid "Thread" #~ msgstr "Нит" #~ msgid "Email Test Result" #~ msgstr "Резултат пробне е-поруке" #~ msgid "Show Weblogging" #~ msgstr "Покажи веб извештај" #~ msgid "Remain/Total" #~ msgstr "Остало/Збир" #~ msgid " or Report ID" #~ msgstr " или Report ID" #~ msgid "Sort by name" #~ msgstr "Поређај по имену" #~ msgid "Sort by age" #~ msgstr "Поређај по старост" #~ msgid "Sort by size" #~ msgstr "Поређај по величини" #~ msgid "Hide files" #~ msgstr "Сакриј датотеке" #~ msgid "Show files" #~ msgstr "Прикажи датотеке" #~ msgid " " #~ msgstr " " #~ msgid "Add new downloads" #~ msgstr "Додај нова преузимања" #~ msgid "WARNINGS" #~ msgstr "УПОЗОРЕЊА" #~ msgid "Complete Dir" #~ msgstr "Фасцикла завршених" #~ msgid "Download speed" #~ msgstr "Брзина преузимања" #~ msgid "Queued" #~ msgstr "У реду" #~ msgid "View script output" #~ msgstr "Видети резултат скрипта" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Неуспешно брисање nzo са реда пост-процесирања (ид)" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "фасцикла \"%s\" не постоји" #~ msgid "SQL Commit Failed, see log" #~ msgstr "Погрешно SQL извршавање, видети извештај" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "CRC грешка у %s (%s -> %s)" #~ msgid "Not matched" #~ msgstr "Не одговара" #~ msgid "OK" #~ msgstr "У реду" #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Изгледа да користите ZoneAlarm на Vista.
" #~ msgid "You have no permisson to use port %s" #~ msgstr "Није Вам дозвољено да користите порт %s" #~ msgid "Initiating restart...
" #~ msgstr "Иницирање поновног покретања...
" #~ msgid "Try again" #~ msgstr "Покушај поново" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Обриши Пар датотеке (ако је успешна провера/поправка)." #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Користити V23 осим ако провајдер захтева другачије!" #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Погрешно ако има yEnc CRC грешке" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Не проверавај са 'par2' када су датотеке 100% важеће." #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "Користи други сервер уколико има CRC грешке." #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "Промени илегална слова у фасцикли по еквиваленти (иначе уклони)." #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "фали 'pyopenssl' модул, инсталирајте га за 'https' приступ" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Фали датотека: %s => грешка 'unrar'?" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "Неуспешан издвој, потребна датотека није распакована" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Неуспешан издвој, ове датотеке недостају:" #~ msgid "Main packet not found..." #~ msgstr "Главни пакет није нађен..." #~ msgid "KB/s" #~ msgstr "КБ/с" #~ msgid "Left" #~ msgstr "остало" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "Нпр 119 или 563 за ССЛ" #~ msgid "Disable API-key" #~ msgstr "Угаси API-кључ" #~ msgid "Get NZB" #~ msgstr "Узми NZB" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Пошаљи: .nzb .rar .zip .gz" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "Склопи датотеке .001, .002 итд у једну датотеку." #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "Склопи датотеке .001.ts, .002.ts итд у једну датотеку." #~ msgid "Filters" #~ msgstr "Филтери" #~ msgid "Check result of unpacking" #~ msgstr "Провери резултат издвоја" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Провери резултат издвоја (треба да се угаси за неке системе датотеке)." #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Погрешне par2 дат., не може да се провери/поправи" #~ msgid "Only for optional servers" #~ msgstr "Само за опционе сервере" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Примени макс покушаје само на опционе сервере" #~ msgid "QR Code" #~ msgstr "QR Код" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "ПАЖЊА: Посао је паузиран \"%s\" јер је RAR датотека шифрована" #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Ваша верзија UNRAR није препоручена, преузети одавде " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "UNRAR програм није нађен, распаковање RAR датотеке није могуће
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "PAR2 програм није нађен, поправка је немогућа
" #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "Посао \"%s\" је опет додат у ред" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "Радови маркирани са '*' неће бити аутоматски преузети." #~ msgid "Downloaded so far" #~ msgstr "За сада преузето" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Немогуће приступити кључу регистра 'HKEY_CURRENT_USER'." #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Немогуће отворити кључ регистра \"%s\"." #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Немогуће читати кључеве регистра за специјалне фасцикле" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd није компатибилан са неким штитним зидовима.
\n" #~ " %s
\n" #~ " Нажалост не можемо одмах да решимо ту некомпатибилност.
\n" #~ " Пошаљите жалбу добављачу штитног зида.
\n" #~ "
\n" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd-у је потребан слободан tcp/ip порт за веб сервер.
\n" #~ " Порт %s на %s је покушан, али налог за SABnzbd нема дозволу да га " #~ "користи.
\n" #~ " На OSX и Linux системима, нормални корисници треба да користе портове " #~ "изнад 1023.
\n" #~ "
\n" #~ " Поново покрените SABnzbd са другим портом." #~ msgid "Purge Failed History" #~ msgstr "Очисти хронологију погрешних" #~ msgid "Delete all failed items from History?" #~ msgstr "Обриши све погрешне ставке са хронологије?" #~ msgid "History Size" #~ msgstr "Величина хронологије" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Промени илегална слова у имену фасцикле" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Користи 12-то датни сат (AM/PM)" #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Упали ако преузимања нису у сопственим фасциклама." #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "Читај Фид ће преузети садржај фида. Натерај " #~ "преузимање јер ће одмах преузети одговарајуће NZB." #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "Желим да SABnzbd буде видљив било којег рачунара моје мреже." #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "Покрени мој претраживач са SABnzbd листом при покретању." #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "После покретања SABnzb-а, можете оведе приступити: %s" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "ПАЖЊА: Поништен рад \"%s\" због шифроване RAR датотеке" #~ msgid "Notification classes" #~ msgstr "Класе нотификације" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "Омогући класе поруке да буду извештене (без, једна или више)" #~ msgid "Error: No secondary interface defined." #~ msgstr "Greška: Sekundarni interfejs nije definisan" #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Greška u uvozu OpenSSL modula. Povezivanje bez SSL" #~ msgid "Secondary Web Interface" #~ msgstr "Sekundarni WEB interfejs" #~ msgid "Activate an alternative skin." #~ msgstr "Aktivirajte alternativni izgled" #~ msgid "Do not require the API key." #~ msgstr "Ne zahtevaj API ključ" #~ msgid "Enable built-in unzip functionality." #~ msgstr "Omogući ugrađenu unzip funkcionalnost" #~ msgid "Enable built-in unrar functionality." #~ msgstr "Omogući ugrađenu unrar funkcionalnost" #~ msgid "Enable Unrar" #~ msgstr "Omogući Unrar" #~ msgid "Enable OZnzb Integration" #~ msgstr "Omogući OZnzb integraciju" #~ msgid "Automatic Feedback" #~ msgstr "Automatske povratne informacije" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Ovaj ključ obezbeđuje indentitet indekseru. Proverite na " #~ "https://www.oznzb.com/profile." #~ msgid "Site API Key" #~ msgstr "API ključ sajta" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "" #~ "Pošalji indekseru automatski izračunate rezultate provere za preuzimanja." #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Proširena funkcionalnost, uključujući ocenjivanje i dodatne informacije o " #~ "statusu, dostupne su pri povezivanju na OZnzb indekser." SABnzbd-2.3.2/po/main/sv.po0000644000000000000000000043630313217005051013464 0ustar 00000000000000# Swedish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2016-02-20 20:34+0000\n" "Last-Translator: shypike \n" "Language-Team: Swedish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:31+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "Det gick inte att starta webbgränssnittet" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "Hittar inte webbmall: %s, försöker med standardmall" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "_yenc modul... EJ funnen!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "par2 binär... EJ funnen!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "" "Din UNRAR version är %s, vi rekommenderar version %s eller högre.
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "unrar binär... EJ funnen!" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "unzip binär... EJ funnen!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "7za binär... EJ funnen!" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "" "Tänk på att värdnamnet 0.0.0.0 behöver en IPv6-adress för extern åtkomst" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "HTTP och HTTPS portar kan inte vara likadana" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "" #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "Avaktiverade HTTPS då CERT och KEY -filer saknas" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "Misslyckades att starta webbgränsnitt: " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "Kan inte nå SABHelper tjänsten" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s startad" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "Varning" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "Fel" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "SABnzbd nedstängning utförd." #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "Adressen är inte angiven." #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "" "Inga anslutningar är aktiverade. Var vänlig aktivera minst en anslutning." #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "Lösenordet är dolt med ******, försök igen" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "Ogiltiga serverdetaljer" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "Timeout: Försök aktivera SSL eller anslut via en annan port." #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "Timeout" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "" #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "Ogiltig serveradress" #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "Servern avslutades under inloggning" #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "Servern kräver användarnamn och lösenord." #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "Anslutning lyckades!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "Autentisering misslyckades, kontrollera användarnamn och lösenord." #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "" "För många anslutningar, pausa en nedladdning eller försök igen senare" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "Det gick inte att ansluta (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "Signal %s mottagen, sparar och stänger..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "Kritiskt fel vid sparande av läge" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "Försöker att hämta NZB från %s" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "Sparar %s misslyckades" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "Kan inte skapa temp -fil för %s" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "Försöker att sätta status på icke existerande server %s" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "Fel i tempfile.mkstemp" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "Laddning av %s misslyckades" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "Laddning av %s misslyckades med fel %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "Testa notifikation" #: sabnzbd/api.py msgid " Resolving address" msgstr " Lösa adress" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "Ingen" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "Standard" #: sabnzbd/api.py msgid "unknown" msgstr "okänd" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "Det gick inte att kompilera regex för sök-sträng: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "För lite diskutrymme pausar systemet" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "Disken är full! Pausar..." #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "Diskfel vid skapande av fil %s" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Kritiskt fel i Assembler" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "Avbruten, kryptering detekterad." #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "" "Varning: I \"%s\" otillåten filändelse i RAR-filen. Otillåtna filen är %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "Oönskad filändelse i RAR-fil %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "Avbruten, oönskad filändelse detekterad" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "VARNING: Pausat jobb \"%s\" pga betyg (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "VARNING: Avbrutet jobb \"%s\" pga betyg (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "Avbrutet, betyget matchade (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "%s saknas" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "" #: sabnzbd/assembler.py msgid "video" msgstr "video" #: sabnzbd/assembler.py msgid "audio" msgstr "ljud" #: sabnzbd/assembler.py msgid "spam" msgstr "spam" #: sabnzbd/assembler.py msgid "passworded" msgstr "lösenordskyddad" #: sabnzbd/assembler.py msgid "downvoted" msgstr "nedröstad" #: sabnzbd/assembler.py msgid "keywords" msgstr "nyckelord" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "Din kvot är uppnådd, pausar nerladdning" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s är inte en godkänd e-mail adress" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "Kräver serveradress" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "Kan inte skapa %s mapp %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "Kan inte skriva till INI filen %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "Kan inte skapa backup-fil för %s" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "Felaktigt kodat lösenord %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s är inte rätt siffervärde" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "UNC sökväg \"%s\" är inte tillåten här" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "Fel: Sökvägen skall vara under %s." #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "Fel: Kön är inte tom, kan inte byta mapp." #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "" "Kan inte skriva till historikdatabasen, kontrollera åtkomsträttigheter!" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "Skadad hitsotrikdatabas, skapade en tom ersättare" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "SQL Kommando misslyckades, se logg" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "Det gick inte att stänga databasen, se logg" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "Felaktig loggning i historiken av %s" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "Avkodning av %s misslyckades" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "Felaktigt utformad yEnc artikel i %s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "Okänt fel under avkodning av %s" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => saknas från alla servrar, kastar" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "Färdig" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "Uppackad %s filer/mappar i %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "Kan ej läsa %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "Det gick inte att lägga till %s, tar bort" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "Fel vid borttagning av %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "Kan ej läsa övervakad mapp %s" #: sabnzbd/downloader.py msgid "Resuming" msgstr "Fortsätter" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "Pausad" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "Du måste ange maximal bandbredd innan du kan ange bandbreddsgräns" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "Server %s kommer att ignoreras i %s minuter" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "Misslyckades att initiera %s@%s med orsak %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "För många anslutningar till servern %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "Misstänkt kontodelning" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "Det gick inte att logga in på server %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "Kan ej ansluta till server %s [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "Anslutning %s@%s misslyckades, meddelande=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "Server %s kräver användarnamn/lösenord" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "Misstänker fel i nedladdare" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "Påbörjar nedstängning av SABnzbd.." #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "Det gick inte att ansluta till mailserver" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "Det gick inte att initialisera TLS anslutning" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "Servern svarade inte ordentligt till hälsningen" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "Autentisering till mailserver misslyckades" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "Ingen passande autentikationsmetod hittades" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "Okänd autentikationmisslyckande i mailservern" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "Det gick inte att skicka e-mail" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "Det gick inte att stänga e-mail anslutning" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "E-mail sändning lyckades" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "Kunde inte skicka, saknar nödvändig data" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "Kan ej finna e-mail mallar i %s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "Ingen mottagare angiven, ingen e-post har skickats" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "Ogiltig avkodning av email mallen %s" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "Inga e-postmallar funna" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "Till: %s\n" "Från: %s\n" "Datum: %s\n" "Ämne: SABnzbd rapporterar att disk är full\n" "\n" "Hej,\n" "\n" "SABnzbd har stoppat nerladdningen på grund av att din disk inte har " "tillräckligt med utrymme kvar.\n" "Frigör utrymme och återuppta nerladdningen manuellt.\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "Varning: LOCALHOST är tvetydigt, använda numerisk IP-adress ." #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "Serveradressen \"%s:%s\" är ej giltig." #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "Saknar sessionsnyckel" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "Fel: Kräver sessionsnyckel" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "Fel: Fel sessionsnyckel" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "" "API-nyckel saknas, skriv in api-nyckeln från Konfiguration-> Allmänt i ditt " "tredjepartsprogram:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "" "API-nyckel felaktig, använd api-nyckeln från Konfiguration-> Allmänt i ditt " "tredjepartsprogram:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "" "Autentisering saknas, ange användarnamn / lösenord från Konfiguration-> " "Allmänt i ditt tredjepartsprogram:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "" "Testa vårat nya tema Glitter! Ny fräsch design som är optimerad för " "stationära och mobila enheter. Gå till Inställningar -> Allmänt för att byta " "tema." #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
SABnzbd nedstängning färdig.
Vänta ungefär 5 sekunder och " "klicka sedan på knappen under..

Ladda " "om
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Flöde" #: sabnzbd/interface.py msgid "Daily" msgstr "Dagligen" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "Måndag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "Tisdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "Onsdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "Torsdag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "Fredag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "Lördag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "Söndag" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "av" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "Odefinerad server!" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "Fel parameter" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "Bakåt" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "FEL:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "Fel värde för %s: %s" #: sabnzbd/misc.py msgid "d" msgstr "d" #: sabnzbd/misc.py msgid "h" msgstr "h" #: sabnzbd/misc.py msgid "m" msgstr "m" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "Kan ej skapa mapp %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "%s mapp: %s åtkomst misslyckad" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "Skapande av (%s) misslyckades" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "Det gick inte att flyta %s till %s" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "Det gick inte att skapa SSL-nyckel eller certifikat." #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "Det gick inte att ändra rättigheter på %s" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "Kör skript" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "Efterbehandling avbröts (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "Skript" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "Nästling för djup [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "Slår ihop" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "Ej komplett sekvens av filer för ihopläggning" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "Filsammanslagning av %s misslyckades" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] Fel \"%s\" under filsammanslagning" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "Fel \"%s\" när du kör file_join på %s" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] Slår ihop %s filer" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "Uppackning misslyckades, %s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] Fel \"%s\" under uppackning av RAR fil(er)" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "Fel \"%s\" när du kör rar_unpack på %s" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "Borttagning av %s misslyckades!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "Försöker att packa upp med lösenord %s" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "Uppackning misslyckades, arkivet kräver lösenord" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "Packar upp" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "Packa upp" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "Uppackning misslyckades, gick inte att hitta %s" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "FEL: gick inte att hitta \"%s\"" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "Uppackning misslyckades, CRC-fel" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "FEL: CRC misslyckades i \"%s\"" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "Uppackning misslyckades, skrivfel eller disken full?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "FEL: skrivningsfel (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "Uppackning misslyckades, sökvägen är för lång" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "FEL: sökvägen är för lång (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "Uppackning misslyckades, se logg" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "FEL: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "Oanvändbar RAR-fil" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s filer i %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "Fel \"%s\" när du kör unzip() på %s" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "Provar 7zip med lösenord \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "7ZIP set \"%s\" är inte komplett, kan inte packa upp" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "Kunde inte packa upp %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "Snabbkontrollerar" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "Reparera" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] Snabbkontroll OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "Startar reparation" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "Par verifiering misslyckades på %s, medans QuickCheck lyckades!" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "Reparation misslyckades, %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "Fel %s när du kör par2_repair på %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "Fel \"%s\" medans par2_repair kördes på %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "" "[%s] PAR2 har fått felaktiga alternativ, ändra dessa via Config->Switches " "inställningarna" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] Verifierad i %s, alla filer är ok" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] Verifiering i %s, kräver reparation" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "Hämtar %s block..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "Hämtar" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "" "Misslyckad reparation, finns ej tillräckligt med reparationsblock (%s saknas)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "Reparerar" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] Reparerad i %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "Disken är full" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "Verifierar" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "Kontrollerar" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "Den här servern tillåter in SSL på denna port" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "Starta/Stäng" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "NZB tillagd" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "Efterbehandling påbörjad" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "Arbetet utförd" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "Jobb misslyckades" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "Kön färdig" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "Andra meddelanden" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "Ej tillgänglig" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "Misslyckades att skicka Prowlmeddelande" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Dålig respons från Pushover (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "Misslyckades att skicka pushovermeddelande" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Dålig respons från Pushbullet (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "Misslyckades att skicka pushbulletmeddelande" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "Gammal kö hittad, använd Status -> Reparera för att konvertera kön" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "Felaktig köfil funnen, kan ej fortsätta" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "Laddningsfel %s, felaktig fil detekterad" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "Misslyckades att starta om NZB efter för-koll (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB tillagd i kön" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> Okänd kodning" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "Fil %s är tom, hoppar över" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "Det gick inte att importera %s filer från %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "NZB filen %s är inte komplett" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "Felaktig NZB fil %s, hoppar över (orsak=%s, linje=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "NZB filen %s är tom" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "Ignorerar dubblett för NZB \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "Pausar dubblett för NZB \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "Avbrutet, kan inte slutföras" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "DUBLETT" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "KRYPTERAT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "FÖR STOR" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "INKOMPLETT" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "OÖNSKAD" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "FILTRERAD" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "VÄNTA %s SEKUNDER" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "Hämtade i %s vid ett genomsnitt på %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "Ålder" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s artiklar var felaktiga" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s artiklar saknades" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s artiklar hade icke-matchande dubletter" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "%s artiklar borttagna" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "Det gick inte att importera %s" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "Varningar" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "Inaktiv" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "Konfiguration" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "Kö" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "Rensa kö" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "Historik" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "Töm historik" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "Hastighetsbegränsning" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "Pausa" #: sabnzbd/osxmenu.py msgid "min." msgstr "min." #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "Återuppta" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "Scanna bevakad mapp" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "Läs alla RSS-flöden" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "Färdig mapp" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "Ofullständig mapp" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "Felsök" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "Starta om" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "Starta om utan login" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "Avsluta" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "Kö (10 första sakerna)" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "Tom" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "Historik (10 senaste sakerna)" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "Ny utgåva tillgänglig" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "Gå till guiden" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "Stänger..." #: sabnzbd/panic.py msgid "Problem with" msgstr "Problem med" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd behöver en ledig tcp/ip -port för sin interna webbserver.
\n" " Port %s på %s testades , men den är inte tillgänglig.
\n" " Någon annan applikation använder porten eller så körs redan " "SABnzbd.
\n" "
\n" " Vänligen starta om SABnzbd med ett annat portnummer." #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "" "Om du får detta felmeddelande igen, var vänlig försök med en annan " "siffra.
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd behöver en giltig värdadress för dess interna webbserver.
\n" " Du har specifierat en ogiltig adress.
\n" " Säkra värdadresser är localhost och 0.0.0.0
\n" "
\n" " Var vänlig starta om SABnzbd med en giltig värdadress." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd har upptäckt sparad data från en annan version av SABnzbd
\n" " men kan inte återanvända datan från det andra programmet.

\n" " Färdigställ dina nedladdningar med det andra programmet först.

\n" " Därefter kan du starta det här programmet med alternativet \"--" "clean\".
\n" " Detta kommando kommer att ta bort din nuvarande kö och historik!
\n" " SABnzbd read the file \"%s\"." #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd kan inte hitta webbgränssnittets filer i %s.
\n" " Var vänlig installera om programmet.
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd upptäckte ett allvarligt fel:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd upptäckte att filen sqlite3.dll saknas.

\n" " Det händer att bristfälligt designade virusprogram tar bort denna " "fil.
\n" " Var vänlig kontrollera ditt virusprogram, försök installera om SABnzbd " "och klaga till din återförsäljare.
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "Tryck på Startknappen+R och skriv raden (exempel):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "Öppna ett Terminal-fönster och skriv raden (exempel):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "Programmet startade inte!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "Allvarligt fel" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "Kan inte starta webbläsaren, hittades troligtvis inte" #: sabnzbd/panic.py msgid "Access denied" msgstr "Åtkomst nekades" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "Error %s: Du måste ange ett giltigt användarnamn och lösenord." #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "" "Nerladdningen kan misslyckas, bara %s av krävda %s finns tillgängligt" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "Nerladdning misslyckades - Inte på din server eller servrar" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "Ingen efterbehandling på grund av misslyckad verifiering" #: sabnzbd/postproc.py msgid "Moving" msgstr "Flyttar" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "Skickat %s till kö" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "Det gick inte att döpa om \"%s\" till \"%s\"" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "Misslyckades med att flytta filer" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "Kör användarskript %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "Körde %s" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "Skriptets utgångskod är %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "Mer" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "Efterbehandling misslyckades för %s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "se loggfil" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "Hämtning misslyckades" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "Rensning av %s misslyckades." #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "Det gick inte att ta bort arbetsmapp (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "Hämtningen slutfördes" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "Kan inte skapa slutgiltig mapp %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "Efterbehandling" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] Ingen par2 sats" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "Försöker verifiera SFV" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "Some files failed to verify against \"%s\"" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "Verifieringen lyckades med SFV-filer" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "Lösenordskyddad" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "Borttagning av %s misslyckades" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "Kunde inte sätta systemet i vänteläge" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "Det gick inte att sätta systemet i viloläge" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "Fel uppstod då systemet skulle stängas" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "Index id (%s) inte hittad för betygsfil" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "Serveradress" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "API-nyckel" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "Felaktigt RSS-flödesbeskrivning \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "Det gick inte att hämta RSS flödet från %s: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "Har inte giltig autentisering för flöde %s" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "Server fel (serverkod %s); kunde inte få %s på %s" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "Server %s använder ett otillförlitlig HTTPS-certifikat" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "RSS-flödet %s var tomt" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "Inkompatibel feed" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "Tom RSS post hittades (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "Visa gränssnitt" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "Öppna färdig mapp" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "Stäng Av" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "Återstår" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "Lägg till NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "Fel schema %s vid %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "Okänd åtgärd: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "Schema för icke existerande server %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "Nedladdning" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "Slår ihop filer" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "Källa" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "Servrar" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "Misslyckades" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "Misslyckades" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "Väntar" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "Reparerar..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "Extraherar..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "Flyttar..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "Kör skript..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "Hämtar extra block..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "Snabbkontroll..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "Verifierar..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "Laddar ner" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "Förekomst" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "Åtgärd" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "Argument" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "Uppgift" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "avaktivera server" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "aktivera server" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "Hastighetsgräns" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "Pausa Allt" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "Pausa efterbehandla" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "Återuppta efterbehandla" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "Läs RSS-flöden" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "Ta bort misslyckade jobb" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "Ta bort färdiga jobb" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "Pausa lågprioriterade jobb" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "Pausa normalprioriterade jobb" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "Pausa högprioriterade jobb" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "Återuppta lågprioriterade jobb" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "Återuppta normalprioriterade jobb" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "Återuppta högprioriterade jobb" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "Aktivera kvothantering" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "Avaktivera kvothantering" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "Av" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "Mycket låg" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "Medel" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "Normal" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "Hög" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "Nödfall" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "Låg" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "MB" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "GB" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "timme" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "timmar" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "min" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "minuter" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "sek" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "sekunder" #: sabnzbd/skintext.py msgid "day" msgstr "dag" #: sabnzbd/skintext.py msgid "days" msgstr "dagar" #: sabnzbd/skintext.py msgid "week" msgstr "vecka" #: sabnzbd/skintext.py msgid "Month" msgstr "Månad" #: sabnzbd/skintext.py msgid "Year" msgstr "År" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "Månadsdag" #: sabnzbd/skintext.py msgid "This week" msgstr "Denna vecka" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "Denna månad" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "I dag" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "Totalt" #: sabnzbd/skintext.py msgid "on" msgstr "den" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "Parametrar" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Python-version" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "Webbplats" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "eller" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "Adress" #: sabnzbd/skintext.py msgid "Comment" msgstr "Kommentar" #: sabnzbd/skintext.py msgid "Send" msgstr "Skicka" #: sabnzbd/skintext.py msgid "Cancel" msgstr "Avbryt" #: sabnzbd/skintext.py msgid "Other" msgstr "Annat" #: sabnzbd/skintext.py msgid "Report" msgstr "Rapportera" #: sabnzbd/skintext.py msgid "Video" msgstr "Video" #: sabnzbd/skintext.py msgid "Audio" msgstr "Ljud" #: sabnzbd/skintext.py msgid "Not used" msgstr "Inte använd" #: sabnzbd/skintext.py msgid "or less" msgstr "eller mindre" #: sabnzbd/skintext.py msgid "Log in" msgstr "" #: sabnzbd/skintext.py msgid "Log out" msgstr "" #: sabnzbd/skintext.py msgid "Remember me" msgstr "" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "Det automatiska usenet nedladdningsverktyget" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "Spara" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "Är du säker?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "Ta bort alla nedladdade filer?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "Hem" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "Konfiguration" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "Status" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "Hjälp" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "Forum" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "Allmänt" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "Mappar" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "Switchar" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "Schemaläggare" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "Meddelanden" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "E-post" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "Kategorier" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "Sortering" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "Speciell" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "Sök" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "Temporär nedladdningmapp" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "PAUSAD" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "Sparat %s artiklar (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "Systembelastning" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "Ny utgåva %s tillgänglig" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "Är du säker på att du vill stänga av SABnzbd?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "Lägg till" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "Lägg till fil" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "Kategori" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "Bearbetar" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "Prioritet" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+Reparera" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+Packar upp" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+Ta bort" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "R" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "P" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "D" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "Tvinga" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "Stopp" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "Ange URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "När kön är färdig" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "Stäng av PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "Sparläge PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "Viloläge PC" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "Stäng av SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "Hastighetsgräns" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "Pausa för" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "Ordning" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "Namn" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "Tid kvar" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "År" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "Ta bort" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "Försök igen" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "Åtgärder" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "Skript" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "Ta bort alla saker från kön?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "Rensa NZB:er" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "Rensa NZB:er och ta bort filer" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "Starta om alla misslyckade jobb" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "Ta bort NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "Ta bort NZB och filer" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "av" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "Saknade artiklar" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "Kvot kvar" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "manuell" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "Återställ Kvot nu" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "Ta bort alla slutförda objekt från Historik?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "Göm detaljer" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "Visa detaljer" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "Visa Misslyckade" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "Visa alla" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "Storlek" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "Rensa Misslyckade NZB:er." #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "Rensa Misslyckade NZB:er och ta bort filer" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "Rensa färdiga NZB:er" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "Valfri Kompletterande NZB" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "Sökväg" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "Starta om alla mysslyckade" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "Starta om alla" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "Virus/spam" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "Slut på retention" #: sabnzbd/skintext.py msgid "Other problem" msgstr "Andra fel" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "Tvinga frånkoppling" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "Detta kommer att skicka ett test e-mail till ditt konto." #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "Visa logg" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "Testa E-post" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "Loggning" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "Fel/Varning" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ Info" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ Debug" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "Anslutningar" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "Senaste Varningar" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "rensa" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "Ta bort blockering" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "Artikel-ID" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "Filuppsättning" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "När" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "Typ" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "Aktiverad" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "Instrumentpanel" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "Anslutning misslyckades!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "Lokal IPv4 adress" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "Publik IPV4 adress" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "IPv6-adress" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "Namnserver /DNS Lookup" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "CPU Modell" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "Systemprestanda (Pystone)" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "Nerladdningsmapphastighet" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "Komplett mapphastighet" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "Skrivhastighet" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "Kunde inte skriva. Kontrollera att sökvägen är skrivbar" #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "Klicka på \"Gör om test\" nedan för att bestämma" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "Gör om test" #: sabnzbd/skintext.py msgid "Config File" msgstr "Konfig fil" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "Använt cache" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "" "Detta kommer att starta om SABnzbd.
Använd det när du tror att " "programmet har stabilitetsproblem.
Nerladdningar kommer att pusas innan " "omstarten och återupptas efteråt." #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "" #: sabnzbd/skintext.py msgid "Advanced" msgstr "" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "" "Det finns övergivna jobb i nedladdningsmappen.
Du kan välja mellan att " "radera dem (inklusive filer) eller skicka tillbaka dem i kön." #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "Ändringarna har inte sparats och kommer att försvinna." #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "" #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "Aktivera Unzip" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "Aktivera 7zip" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "" #: sabnzbd/skintext.py msgid "Version" msgstr "Version" #: sabnzbd/skintext.py msgid "Uptime" msgstr "Upptid" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "Säkerhetskopiera" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "Läs Wiki Help för detta!" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "Startar om SABnzbd..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "Ändringar kräver omstart av SABnzbd!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "SABnzbd Webbserver" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "SABnzbd Adress" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "Adress som SABnzbd ska lyssna på." #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "SABnzbd-port" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "Port som SABnzbd ska lyssna på." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Webbkontrollsutseende" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "Välj ett skin." #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "SABnzbd Användarnamn" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "Väljbart autentiserings användarnamn." #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "SABnzbd Lösenord" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "Väljbart autentiserings lösenord." #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "HTTPS Aktivera" #: sabnzbd/skintext.py msgid "not installed" msgstr "inte installerad" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "Aktivera åtkomst till webbkontrollen med HTTPS adress." #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "HTTPS-port" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "Om tom kommer standardporten endast lyssna till HTTPS." #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "HTTPS Certifikat" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "Filnamn eller sökväg till HTTPS Certifikat." #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "HTTPS Nyckel" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "Filnamn eller sökväg till HTTPS Nyckel." #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "HTTPS-kedjecertifikat" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "Filnamn eller sökväg till HTTPS-kedja" #: sabnzbd/skintext.py msgid "Tuning" msgstr "Optimering" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "RSS Uppdateringsintervall" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "" "Kontrollintervall (i minuter, minst 15). Ej aktiv om du använder " "Schemaläggaren!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "Maximal linjehastighet" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "Procent av linjehastighet" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "Vilken procent av linjehastigheten ska SABnzbd använda, te.x 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "Cachestorlek för artiklar" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "Sparar artiklar i minnet för att reducera diskåtkomst.
I bytes, " "följt av K,M,G. Till exempel: \"64M\" eller \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "Rensa lista" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "" "Lista av filändelser som skall bli borttagna efter nerladdning.
Till " "exempel: nfo or nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "Spara ändringar" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "Återställ" #: sabnzbd/skintext.py msgid "Language" msgstr "Språk" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "Välj språk till webbkontrollen." #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "Denna nyckel ger tredjepartsprogram full tillgång till SABnzbd." #: sabnzbd/skintext.py msgid "NZB Key" msgstr "NZB-nyckel" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "" "Denna nyckel ger tredjepartsprogram möjlighet att lägga till NZB:er i " "SABnzbd." #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "Generera Ny Nyckel" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "API- eller QR-kod" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "Lista av lokala nätverksomfång" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "" "Alla lokala nätverksadresser startar med dessa prefixer (ofta \"192.168.1.\")" #: sabnzbd/skintext.py msgid "External internet access" msgstr "Extern internetåtkomst" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "" #: sabnzbd/skintext.py msgid "No access" msgstr "Ingen åtkomst" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "Lägg till NZB-filer " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (ingen Konfigurering)" #: sabnzbd/skintext.py msgid "Full API" msgstr "Full API" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "Fullt Webgränsnitt" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "" "OBS: Mappar kommer att skapas automatiskt när du Sparar. Du måste " "ange exakta sökvägar till dina mappar för att spara utanför standardmapparna." #: sabnzbd/skintext.py msgid "User Folders" msgstr "Användarmappar" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "Bläddra" #: sabnzbd/skintext.py msgid "In" msgstr "I" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "Temporär nedladdningsmapp" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "" "Plats för att lagra ej bearbetade nedladdningar.
Kan endast ändras " "när kön är tom." #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "Minimal fri plats för temporär nedladdningsmapp" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "Auto-pausa när fri plats är nära sin gräns.
I bytes, följt av " "K,M,G,T. Till exempel: \"800M\" or \"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "Färdig nedladdningsmapp" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "" "Plats för att lagra bearbetade och färdiga nedladdningar.
Kan " "åsidosättas av användar-definierade kategorier." #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "Rättigheter för färdiga nedladdningar" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "" "Sätt rättigheter för färdiga filer och mappar.
Använd siffror. Till " "exempel: \"755\" or \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "Övervakad Mapp" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "Mapp som igenomsöks automatiskt efter .nzb filer.
Skannar även " "igenom .zip .rar och .tar.gz arkiv efter .nzb filer." #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "Skanningsintervall för Övervakade mappar" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "Sekunder mellan skanningar för .nzb filer." #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "Mapp för E-mail mallar" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "Mapp som innehåller användar-definierade e-mail mallar." #: sabnzbd/skintext.py msgid "Password file" msgstr "Lösenordsfil" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "" "Fil som innehåller alla lösenord som ska prövas på krypterade RAR-filer." #: sabnzbd/skintext.py msgid "System Folders" msgstr "Systemmappar" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "Administrativ mapp" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "" "Plats för köadministration och historiedatabas.
Kan bara ändras när " "kön är tom." #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "Data kommer inte tas bort. Kräver omstart av SABnzbd!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "Loggmapp" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "" "Plats för sparade loggfiler från SABnzbd.
Kräver omstart av " "SABnzbd!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr ".nzb Reservmapp" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "Plats där .nzb filer sparas." #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "Standard basmapp" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "Ladda ner alla par2 filer" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "Aktivera rekursiv uppackning" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "Packa upp arkiv (rar,zip,7z) inuti arkiven." #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "Ignorera alla mappar i arkiven" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "Alla filer kommer hamna i en mapp." #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "Bara artiklarna för början av kön" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "" "Aktivera för lägre minnesanvändning. Avaktivera för att förhindra långsamma " "jobb att blockera kön." #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "Efterbehandla endast verifierade jobb" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "Efterbehandla enbart jobb som passerat PAR2 kontrollen." #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "Händelse när krypterade RAR är nerladdad" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "" "Om \"Pausad\", så behöver du ange ett lösenord för att återuppta jobbet." #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "Upptäck dubbletter av nedladdningar" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "Hitta dublettavsnitt i serier" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "Kasta" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "Avbryt" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "Händelse när oönskad filändelse hittad" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "Händelse när en oönskad filändelse är hittad i RAR-filer." #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "Oönskade filändelser" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "" "Lista alla oönskade filändelser. Till Exempel: exe or exe, com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "Använd SFV-baserade kontroller" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "Gör en extra kontroll med SFV filer" #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "Användarskript kan flagga jobb som misslyckat" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "" "När ett användarskript returnerar ett icke-nollutgångsvärde, så kommer " "jobbet att flaggas som misslyckat" #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "När misslyckat, prova en alternativ NZB" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "" "Vissa servrar kan förse en alternativ NZB när en nerladdning misslyckas" #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "Döp om mappar" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "" "Använd temporära namn under efterbehandling. Avslaget när ditt system inte " "stöder det." #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "Kö-specifika användarskript" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "Används innan en NZB tas in i kön." #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "Extra PAR2 parametrar" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Bra parametrar" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "IONice parametrar" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "Koppla ifrån när kön är tom" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "Koppla ifrån usenet servrarna när kön är tom eller pausad." #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "Sortera efter ålder" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "Sortera automatiskt efter (medel) ålder." #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "" #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "Kolla efter ny utgåva" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "Kolla efter ny utgåva av SABnzbd varje vecka." #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "Även testutgåvor" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "Ersätt mellanslag i mappnamn" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "Ersätt mellanslag med understreck i mappnamn." #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "Ersätt punkter i mappnamn" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "Ersätt punkter med mellanslag i mappnamn" #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "Gör Windows-kompatibel" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "För servrar: Gör att namn är kompatibla med Windows." #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "Starta webbläsare vid uppstart" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "Startar standard webbläsaren när SABnzbd startar." #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "Pausa nedladdning under efterbehandling" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "" "Pausas nedladdning när efterbehandling börjar och återupptar nedladdning när " "efterbehandling är klar." #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "Ignorera Sample-filer" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "Filtrera ut sample-filer (ex. video samplingar)." #: sabnzbd/skintext.py msgid "Delete after download" msgstr "Ta bort efter nedladdning" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "" #: sabnzbd/skintext.py msgid "Server" msgstr "Server" #: sabnzbd/skintext.py msgid "Post processing" msgstr "Efterbehandling" #: sabnzbd/skintext.py msgid "Naming" msgstr "Döpning" #: sabnzbd/skintext.py msgid "Quota" msgstr "Kvot" #: sabnzbd/skintext.py msgid "Indexing" msgstr "Indexerar" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "Hur mycket kan laddas ner denna månad (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "Nollställ dag" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "" "På vilken dag i månaden eller veckan (1=Måndag) nollställer din ISP din " "kvot? (Alternativt med hh:mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "Autoåterupptagning" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "Skall nerladdning återupptas efter att kvot är nollställd?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "Kvotperiod" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "Nollställs kvoten varje dag, vecka eller månad?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "Kontrollera innan nerladdning" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "" "Försök att förutspå lyckad överföring innan nerladdningen påbörjas (saktare!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "Max antal omförsök" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "Max antal omförsök per server" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "Avbryt jobb som inte kan kompletteras" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "" "Under nerladdning och det märks att för mycket data saknas, avbryt jobbet" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "Aktivera Filtrering" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "Action nedladdningar enligt filtreringsregler." #: sabnzbd/skintext.py msgid "Abort If" msgstr "Avbryt Om" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "Annars Pausa Om" #: sabnzbd/skintext.py msgid "Video rating" msgstr "Videobetyg" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "Audiobetyg" #: sabnzbd/skintext.py msgid "Spam" msgstr "Spam" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "Bekräftad" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "Fler tummar ner än upp" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "Titelns nyckelord" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "Kommaseparerad lista" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "Serverbelastad-balansering" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "Undvik belastningsbalansering" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "Tillåt belastningsbalansering" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "Tillåt bellastningsbalansering med optimering för IPv6" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "Användbar om en newsserver har fler val än en IPv4/IPv6adress" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "Lägg till server" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "Serverbeskrivning" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "Port" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "Användarnamn" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "Lösenord" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "Tidsgräns" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "Retensionstid" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "Avaktiverad" #: sabnzbd/skintext.py msgid "Minimal" msgstr "" #: sabnzbd/skintext.py msgid "Strict" msgstr "" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 är högst prioritet, 100 är lägst prioritet" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "Valfri" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "Aktivera" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "Ta bort server" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "Testserver" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "Nollställ räknare" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "Testar serverdetaljer..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "Bandbredd" #: sabnzbd/skintext.py msgid "Send Group" msgstr "Skicka grupp" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "Skicka gruppkommando innan du begär artiklar." #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "Använd endast denna server för dessa kategorier." #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "" #: sabnzbd/skintext.py msgid "Personal notes" msgstr "Personliga noteringar" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "Lägg till schema" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "Aktuella scheman" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "Kryssrutan bredvid flödesnamnet ska aktiveras för att flödet automatiskt ska " "kontrolleras för nya objekt.
När ett flöde läggs till kommer det bara " "att välja nya objekt och inte allt som redan finns i RSS-flöded så länge du " "inte klickar på \"Tvinga nedladdning\"." #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "Läs flöde" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "Tvinga nedladdning" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "Filter" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "Acceptera" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "Avvisa" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "Kräver" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "KräverKat" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "Minst" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "Högst" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "Från SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "Matchade" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "Inte Matchade" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "Nedladdad" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "Läsa Alla Flöden Nu" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "E-post notifiering när jobb är slutfört" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "Aldrig" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "Alltid" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "Bara vid fel" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "Full hårddisk notifiering" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "Skicka e-mail när hårddisken är full och SABnzbd har pausat." #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "Skicka RSS-notiser" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "Skicka E-post när ett RSS-flöde lägger till jobb till kön." #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "SMTP-server" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "Ställ in din ISP's server för utgående e-mail." #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "E-post mottagare" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "E-postadress att skicka e-post till." #: sabnzbd/skintext.py msgid "Email Sender" msgstr "E-post avsändare" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "Vem ska vi skicka e-posten från?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "VALFRITT Kontoanvändarnamn" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "Användarnamn för e-post som kräver autentisering." #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "VALFRITT Användarlösenord" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "Lösenord för e-post som kräver autentisering." #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "Aktivera Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "Skicka notis till Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "Använd endast för extern Growl.server (host:port)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "Serverlösenord" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Valfritt lösenord för Growl-server" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "Aktivera NotifyOSD" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "Skicka notiser till NotifyOSD" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "Meddelandecenter" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "Skicka notiser till Meddelandecenter" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "Aktivera Windows-notiser" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Windows-notiser" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "NotifyOSD" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "Aktivera Prowl-notiser" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "Kräver ett Prowl-konto" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "API-nyckel för Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Personlig API-nyckel för Prowl (krävs)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "Aktivera Pushover-notiser" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "Kräver ett Pushover-konto" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "Applikations Token" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "Applikations token (krav)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "Användarnyckel" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "Användarnyckel (krävs)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "Enhet(er)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "Enhet(er) där medellandet skall skickas" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "Aktivera Pushbullet-notiser" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "Kräver ett Pushbullet-konto" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "Personlig API-nyckel" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "Din personliga API-nyckel (krävs)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "Enhet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "Enheter där meddelande skall skickas" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "" "Avsluta sökvägen med en asterisk * kommer förhindra jobb att skapa mappar" #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "Relativa mappar är baserade på" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "Mapp/Sökväg" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "Seriesortering" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "Aktivera TV sortering" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "Hjälp till Sorteringssträng" #: sabnzbd/skintext.py msgid "Clear" msgstr "Rensa" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "" #: sabnzbd/skintext.py msgid "Presets" msgstr "Förinställningar" #: sabnzbd/skintext.py msgid "Example" msgstr "Exempel" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "Aktivera filmsortering" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "Låt nedladdning i extramapp vara" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "Påverkade kategorier" #: sabnzbd/skintext.py msgid "Meaning" msgstr "Betyder" #: sabnzbd/skintext.py msgid "Pattern" msgstr "Mönster" #: sabnzbd/skintext.py msgid "Result" msgstr "Resultat" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 Säsongsmapp" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 Säsongsmapp" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 Episodmapp" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 Episodmapp" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "Titel" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "Film Namn" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "Film.Namn" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "Film_Namn" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "Show Namn" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "Show.Namn" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "Show_Namn" #: sabnzbd/skintext.py msgid "Season Number" msgstr "Säsongsnummer" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "Episodnummer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "Episodnamn" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "Episod.Namn" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "Episod_Namn" #: sabnzbd/skintext.py msgid "File Extension" msgstr "Filändelse" #: sabnzbd/skintext.py msgid "Extension" msgstr "Filändelse" #: sabnzbd/skintext.py msgid "Part Number" msgstr "Delnummer" #: sabnzbd/skintext.py msgid "Decade" msgstr "Årtionde" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "Originalfilnamn" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "Små bokstäver" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEXT" #: sabnzbd/skintext.py msgid "text" msgstr "text" #: sabnzbd/skintext.py msgid "file" msgstr "fil" #: sabnzbd/skintext.py msgid "Sort String" msgstr "Sorteringssträng" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "Multi-del etikett" #: sabnzbd/skintext.py msgid "In folders" msgstr "In mapp" #: sabnzbd/skintext.py msgid "No folders" msgstr "Ingen mapp" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "Datum sortering" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "Aktivera datumssortering" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "Visa Namn på mapp" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "År-Månads mappar" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "Dagliga mappar" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "versal-justerade" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "Hanterade resultat" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "Sällan använda inställningar. För deras mening och förklaring, klicka på " "Hjälpknappen för att komma till Wiki-sidan.
Ändra inte dessa utan att " "kolla med Wiki först, då vissa kan ha seriösa " "sidoeffekter.
Standardvärdet är mellan paranteser." #: sabnzbd/skintext.py msgid "Values" msgstr "Värden" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "Ändra NZB detaljer" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "Ta bort" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "Topp" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "Upp" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "Ner" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "Botten" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "Alla" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "Invertera" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "Filnamn" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "Ämne" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "Urval" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "Pausa 5 minuter" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "Pause 15 minuter" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "Pausa 30 minuter" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "Pausa 1 timme" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "Pausa 3 timmar" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "Pausa 6 timmar" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "kvar" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "Ledigt diskutrymme" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "Temporär Mapp" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "Multi-operationer" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "Håll in shiftknappen för att välja omfång" #: sabnzbd/skintext.py msgid "Check all" msgstr "Markera alla" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "Starta om SABnzbd" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "Status och gränsnittsinställningar" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "Eller dra och släpp filer i fönstret!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "Förlorade förbindelse till SABnzbd.." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "Om SABnzbd startar om kommer denna skärm att försvinna automatiskt!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "VARNING:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "Hämta" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "Uppdateringsfrekvens" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "Använda globala gränsnittsinställningar" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "Kö artikelgräns" #: sabnzbd/skintext.py msgid "History item limit" msgstr "Historik artikelgräns" #: sabnzbd/skintext.py msgid "Date format" msgstr "Datumformat" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "Extra kökolumn" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "sida" #: sabnzbd/skintext.py msgid "Loading" msgstr "Laddar" #: sabnzbd/skintext.py msgid "articles" msgstr "artiklar" #: sabnzbd/skintext.py msgid "Rename" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "Köreparation" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "Visa aktiva anslutningar" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "Övergivna jobb" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "Skicka tillbaka i kön" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "Ta bort alla" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "Starta om alla" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "Hämta NZB från URL" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "Ladda upp NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "Alternativt ange ett filnamn" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "Format: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "Skicka" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "Öppen informations URL" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "Skickat. Tack!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "Inget markerat!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "Ta bort alla markerade filer" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "Visa/göm färdiga filer" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "Visa skriptlogg" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "Uppdatering tillgänglig" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "Anpassa" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "Hastighet" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "Bekräfta Kö-borttagningar" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "Bekräfta Historik-borttagningar" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "Hur lång tid eller tills då vill du pausa? (på engelska!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "Tyvärr, vi kunde inte tolka det. Försök igen." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "Pausa i..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "Uppdatera" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "Sortera efter ålder Äldst→Nyast" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "Sortera efter ålder Nyast→Äldst" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "Sortera efter namn A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "Sortera efter namn Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "Sortera efter storlek Minst→Störst" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "Sortera efter storlek Störst→Minst" #: sabnzbd/skintext.py msgid "Uploading" msgstr "" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "" #: sabnzbd/skintext.py msgid "Removing job" msgstr "" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "Föregående" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "Nästa" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "Vill du verkligen tömma historiken?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "Du måste aktivera JavaScript för Plush ska fungera!" #: sabnzbd/skintext.py msgid "Options" msgstr "Alternativ" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "Pausa hur många minuter?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "Menyrad" #: sabnzbd/skintext.py msgid "On Finish" msgstr "Vid slut" #: sabnzbd/skintext.py msgid "Sort" msgstr "Sortera" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "Sortera efter Ålder (Äldst→Nyast)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "Sortera efter Ålder (Nyast→Äldst)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "Sortera efter Namn (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "Sortera efter Namn (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "Sortera efter Storlek (Minst→Störst)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "Sortera efter Storlek (Störst→Minst)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "Töm kön?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "Starta om alla misslyckade jobb i historik?" #: sabnzbd/skintext.py msgid "Purge" msgstr "Rensa" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "Max hastighet" #: sabnzbd/skintext.py msgid "Range" msgstr "Omfång" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "Applicera på valda" #: sabnzbd/skintext.py msgid "Everything" msgstr "Allt" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "Uppdateringsintervall" #: sabnzbd/skintext.py msgid "Container Width" msgstr "Bredd av webbplats" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "" "Detta kommer förhindra uppdaterande av innehåll när din muspekare svävar " "ovanför kön" #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "Block uppdaterar vid svävande" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "Ladda upp" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "Ladda upp: .nzb .rar .zip .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "Förlopp" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "Inte tillräckligt med diskutrymme för att kunna fortsätta ladda ned." #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "Ledigt temputrymme" #: sabnzbd/skintext.py msgid "IDLE" msgstr "Väntar" #: sabnzbd/skintext.py msgid "Downloads" msgstr "Hämtningar" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "Borttagning färdig" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "Ta bort alla felaktiga saker från historiken?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "Borttagning Misslyckades" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "Starta om alla misslyckade jobb?" #: sabnzbd/skintext.py msgid "Links" msgstr "Länkar" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "Visar %s till %s av %s resultat" #: sabnzbd/skintext.py msgid "No results" msgstr "Inga träffar" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "Visar ett resultat" #: sabnzbd/skintext.py msgid "First" msgstr "Första" #: sabnzbd/skintext.py msgid "Last" msgstr "Sista" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "Skickat E-mail!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "Notis skickad!" #: sabnzbd/skintext.py msgid "Saving.." msgstr "Sparar.." #: sabnzbd/skintext.py msgid "Saved" msgstr "Sparad" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "Visa/Dölj Lägg till NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "Flerskärm1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "Flerskärm2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "Är du säker på att du vill starta om SABnzbd?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "Dölj Redigeringsalternativ" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "Visa Redigeringsalternativ" #: sabnzbd/skintext.py msgid "Edit" msgstr "Ändra" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "Återstående tid" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "SABnzbd Snabbstart Guide" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "SABnzbd Version" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "Föregående" #: sabnzbd/skintext.py msgid "Server Details" msgstr "Serveruppgifter" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "Fyll i uppgifter om din primära usenet leverantör." #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "Antalet anslutningar som tillåts av din leverantör" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "Te.x 8 eller 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "Välj bara om din leverantör tillåter SSL-anslutningar." #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "Klicka här för att testa dina angivna serveruppgifter." #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "T.ex." #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "Installationen är nu utförd!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd kommer nu att köras i bakgrunden." #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "" "SABnzbd kommer inte att stängas av om du stänger ett fönster eller en tab i " "webbläsaren." #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "" "Det är rekommenderat att du sparar denna plats som ett bokmärke för att " "komma åt SABnzbd när det körs i bakgrunden." #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "Övrig hjälp kan du hitta på våran" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "Gå till SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "Avsluta SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "Starta guide" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd har ABSOLUT INGEN GARANTI\n" "Detta är gratis mjukvara, du är välkommen att sprida det under vissa " "omständigheter.\n" "Det är licensierat under GNU GENERAL PUBLIC LICENSE Version 2 eller (ditt " "val) en senare version.\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "" "För att ladda ner från usenet du behöver tillgång till en leverantör. Din " "internetleverantör kan ge dig tillgång, men en premie leverantör " "rekommenderas." #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "Har du inte någon usenet leverantör? Vi rekommenderar att prova %s." #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "Det gick inte att hämta TV info (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "Det gick inte att döpa om: %s till %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "Det gick inte att döpa om liknande fil: %s till %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "Servernamn kunde inte läsas" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "Otillåten åtkomst" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "URLGRABBER KRASHADE" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "Oanvändbar NZB fil" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "URL hämtning misslyckades; %s" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "Mappen \"%s\" finns inte" #~ msgid "SQL Commit Failed, see log" #~ msgstr "SQL Commit misslyckades, se logg" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "CRC Fel i %s (%s -> %s)" #~ msgid "Error: No secondary interface defined." #~ msgstr "Fel: Inget andrainterface definierat." #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "" #~ "Din version av UNRAR rekommenderas inte, få UNRAR från " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "Inget UNRAR program funnet, uppackning ej möjlig
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "Inget PAR2 program funnet, reparation ej möjlig
" #~ msgid "Initiating restart...
" #~ msgstr "Förbereder omstart...
" #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "Jobb \"%s\" är återinlagt i kön" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "Jobb markerade med '*' kommer ej att laddas ned automatiskt." #~ msgid "Not matched" #~ msgstr "Matchade inte" #~ msgid "Downloaded so far" #~ msgstr "Nedladdade än så länge" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "Kan ej ansluta till registret HKEY_CURRENT_USER." #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "Kan ej öppna registernyckel \"%s\"." #~ msgid "Failed to read registry keys for special folders" #~ msgstr "Det gick inte att läsa registernyckel för specialmappar" #~ msgid "You have no permisson to use port %s" #~ msgstr "Du har ingen behörighet för att använda port %s" #~ msgid "Try again" #~ msgstr "Försök igen" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "pyopenssl modul saknas, var vändlig installera för https åtkomst" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "Saknade förväntad fil: %s => unrar fel?" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "Uppackning misslyckades, en väntad fil är inte uppackad" #~ msgid "Main packet not found..." #~ msgstr "Huvudarkiv saknas..." #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "Misslyckades med importering av OpenSSL modul. Ansluter utan SSL" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "Det gick inte att ta bort nzo från efterbehandlings kön (id)" #~ msgid "View script output" #~ msgstr "Visa skriptutmatning" #~ msgid "Queued" #~ msgstr "Köad" #~ msgid "Complete Dir" #~ msgstr "Färdig nedladdningsmapp" #~ msgid "Download speed" #~ msgstr "Nedladdningshastighet" #~ msgid "WARNINGS" #~ msgstr "VARNINGAR" #~ msgid "Add new downloads" #~ msgstr "Lägg till ny nedladdning" #~ msgid " or Report ID" #~ msgstr " eller Report ID" #~ msgid "Sort by name" #~ msgstr "Sortera efter namn" #~ msgid "Sort by age" #~ msgstr "Sortera efter ålder" #~ msgid "Sort by size" #~ msgstr "Sortera efter storlek" #~ msgid "Hide files" #~ msgstr "Göm filer" #~ msgid "Show files" #~ msgstr "Visa filer" #~ msgid "Remain/Total" #~ msgstr "Återstår/Totalt" #~ msgid "History Size" #~ msgstr "Historikstorlek" #~ msgid "Show Weblogging" #~ msgstr "Visa webblogg" #~ msgid "Thread" #~ msgstr "Tråd" #~ msgid "General configuration" #~ msgstr "Allmän konfiguration" #~ msgid "Secondary Web Interface" #~ msgstr "Andra Webbkontrollsutseende" #~ msgid "Activate an alternative skin." #~ msgstr "Aktivera ett alternativt skin." #~ msgid "Web server authentication" #~ msgstr "Webbserver autentiserng" #~ msgid "HTTPS Support" #~ msgstr "HTTPS Stöd" #~ msgid "Queue auto refresh interval:" #~ msgstr "Automatisk uppdateringsintervall av kö:" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "Uppdateringsintervall av kö-sidan (sek, 0= ingen)." #~ msgid "Disable API-key" #~ msgstr "Stäng av API-nyckel" #~ msgid "Do not require the API key." #~ msgstr "Kräv ingen API-nyckel." #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "ANVÄND PÅ EGEN RISK!" #~ msgid "Folder configuration" #~ msgstr "Mappkonfiguration" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "Efterbehandlings skriptmapp" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "Mapp innehållande skript för efterbehandling." #~ msgid "Switches configuration" #~ msgstr "Parameterkonfiguration" #~ msgid "Processing Switches" #~ msgstr "Bearbetar parametrar" #~ msgid "Enable Quick Check" #~ msgstr "Aktivera Snabbkoll" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "Strunta i par2 kontroll när filerna är 100% giltiga." #~ msgid "Enable Unrar" #~ msgstr "Aktivera Unrar" #~ msgid "Enable built-in unrar functionality." #~ msgstr "Aktiverar inbyggda Unrar funktionen." #~ msgid "Enable built-in unzip functionality." #~ msgstr "Aktiverar inbyggda Unzip funktionen." #~ msgid "Enable Filejoin" #~ msgstr "Aktivera Filsammanslagning (Filejoin)" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "Slår ihop filer med filändelserna .001, .002 etc. till en fil." #~ msgid "Enable TS Joining" #~ msgstr "Aktivera TS Sammanslagning (TS Joining)" #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "Slår ihop filer med filändelserna .001.ts, .002.ts etc. till en fil." #~ msgid "Enable Par Cleanup" #~ msgstr "Aktivera Par rensning (Par Cleanup)" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "Rensar bort par filer (om verifiering/reparation lyckades)." #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "Vid fel på på yEnc CRC" #~ msgid "Default Post-Processing" #~ msgstr "Standard efterbehandling" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "Används när efterbehandlingen är bestämd efter kategori." #~ msgid "Default User Script" #~ msgstr "Standard användarskript" #~ msgid "Used when no user script is defined by the category." #~ msgstr "Används när användarskript är bestämd efter kategori." #~ msgid "Default Priority" #~ msgstr "Standard prioritet" #~ msgid "Used when no priority is defined by the category." #~ msgstr "Använd när ingen prioritet är bestämd av kategori." #~ msgid "Enable MultiCore Par2" #~ msgstr "Aktivera MultiCore Par2" #~ msgid "Other Switches" #~ msgstr "Andra parametrar" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "Ersätt otillåtna tecken i mappnamn." #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "" #~ "Ersätt otillåtna tecken i mappnamn med motsvarande tecken (annars ta bort)." #~ msgid "Do not download" #~ msgstr "Ladda inte ned." #~ msgid "SSL type" #~ msgstr "SSL typ" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "Använd V23 om inte din leverantör kräver annat!" #~ msgid "Server configuration" #~ msgstr "Serverkonfiguration" #~ msgid "Backup server" #~ msgstr "Reserv server" #~ msgid "Click below to test." #~ msgstr "Klicka nedan för att testa." #~ msgid "Scheduling configuration" #~ msgstr "Schemakonfiguration" #~ msgid "Remove" #~ msgstr "Ta bort" #~ msgid "RSS Configuration" #~ msgstr "RSS-konfiguration" #~ msgid "New Feed URL" #~ msgstr "Ny flödesadress" #~ msgid "Delete Feed" #~ msgstr "Ta bort flöde" #~ msgid "Email Options" #~ msgstr "E-mail alternativ" #~ msgid "Email Account Settings" #~ msgstr "E-mail kontoinställningar" #~ msgid "User-defined categories" #~ msgstr "Användardefinierade kategorier" #~ msgid "Defines post-processing and storage." #~ msgstr "Definierar efterbehandling och lagring." #~ msgid "Sorting configuration" #~ msgstr "Sorteringskonfiguration" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "Aktiverar sortering och omdöpning av episoder." #~ msgid "Generic Sorting" #~ msgstr "Allmän sortering" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "Aktiverar sortering och omdöpning av filer." #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "Aktivera om nedladdning inte är flyttad till egen mapp." #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "Aktiverar sortering och omdöpning av datummärkta filer." #~ msgid "Are you sure you want to delete" #~ msgstr "Är du säker på att du vill ta bort" #~ msgid "Page" #~ msgstr "Sida" #~ msgid "Close" #~ msgstr "Stäng" #~ msgid "Set Pause Interval" #~ msgstr "Sätt pausintervall" #~ msgid "Pause Interval" #~ msgstr "Pausintervall" #~ msgid "Pause for 12 hours" #~ msgstr "Pausa 12 timmar" #~ msgid "Pause for 24 hours" #~ msgstr "Pausa 24 timmar" #~ msgid "Left" #~ msgstr "Vänster" #~ msgid "Open Source URL" #~ msgstr "Öppen källdkod URL" #~ msgid "Storage" #~ msgstr "Lagring" #~ msgid "Plush Options" #~ msgstr "Plush Inställningar" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "Ladda upp: .nzb .rar .zip .gz" #~ msgid "Hour:Min" #~ msgstr "Timme:Minut" #~ msgid "Access" #~ msgstr "Åtkomst" #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "" #~ "Jag vill att SABnzbd ska bli nåbart från vilken dator som helst i mitt " #~ "nätverk." #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "Jag vill att SABnzbd ska bli nåbart enbart från min dator." #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "Lösenordsskydda åtkomst till SABnzbd (rekommenderas)" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "Aktivera HTTPS åtkomst till SABnzbd." #~ msgid "Misc" #~ msgstr "Diverse" #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "Starta webbläsaren med SABnzbd's sida när programet startas." #~ msgid "This field is required." #~ msgstr "Detta fält krävs." #~ msgid "Please enter a whole number." #~ msgstr "Ange ett heltal." #~ msgid "Step One" #~ msgstr "Steg ett" #~ msgid "Step Two" #~ msgstr "Steg två" #~ msgid "Step Three" #~ msgstr "Steg tre" #~ msgid "Step Four" #~ msgstr "Steg fyra" #~ msgid "Step Five" #~ msgstr "Steg fem" #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "Korrupta par2 filer, kan inte verifiera eller reparera" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "Uppackning misslyckades, dessa filer saknas:" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd är inte kompatibelt med vissa mjukvarubaserade brandväggar.
\n" #~ " %s
\n" #~ " Tyvärr kan vi inte lösa denna inkompatibilitet just nu.
\n" #~ " Vänligen registrera ett klagomål hos brandväggens tillverkare.
\n" #~ "
\n" #~ msgid "OK" #~ msgstr "OK" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd behöver en tillgänglig tcp/ip port för dess interna web " #~ "server.
\n" #~ " Port %s på %s testades, men kontot som används för SABnzbd har inte " #~ "tillåtelse att använda den.
\n" #~ " På OSX och Linux-system måste normala användare använda portnummer 1023 " #~ "eller högre.
\n" #~ "
\n" #~ " Var vänlig starta om SABnzbd med ett annat portnummer." #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "Det är troligt att du använder ZoneAlarm på Vista.
" #~ msgid "Get NZB" #~ msgstr "Lägg till NZB" #~ msgid "KB/s" #~ msgstr "KB/s" #~ msgid " " #~ msgstr " " #~ msgid "Purge Failed History" #~ msgstr "Rensa Misslyckad Historik" #~ msgid "Delete all failed items from History?" #~ msgstr "Ta bort alla misslyckade objekt från Historik?" #~ msgid "QR Code" #~ msgstr "QR-kod" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "" #~ "När artiklars CRC-kontrollsumma ger fel, försök att hämta dem från en annan " #~ "server." #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "" #~ "Kontrollera resultat av uppackning (måste slås av på vissa filsystem)." #~ msgid "Check result of unpacking" #~ msgstr "Kontrollera resultat av uppackning" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "Varning: avbröt jobbet %s på grund av att RAR-filen är krypterad" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "VARNING: Pausat jobb \"%s\" då RAR-filen är krypterad" #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "" #~ "Efter att SABnzbd har startat om kommer du att hitta det vid angivna " #~ "platsen: %s" #~ msgid "Email Test Result" #~ msgstr "E-posta testresultat" #~ msgid "Only for optional servers" #~ msgstr "Endast för vissa servers" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "Applicera endast max antal omförsök till vissa servers" #~ msgid "Site API Key" #~ msgstr "Sidans API-nyckel" #~ msgid "Enable OZnzb Integration" #~ msgstr "Aktivera OZnzb-integration" #~ msgid "Automatic Feedback" #~ msgstr "Automatisk Feedback" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "" #~ "Denna nyckel ger indentitet till index. Refererar till " #~ "https://www.oznzb.com/profile." #~ msgid "Skip" #~ msgstr "Hoppa över" #~ msgid "Groups / Indexer tags" #~ msgstr "Grupper/Indexering-tagg" #~ msgid "folder" #~ msgstr "mapp" #~ msgid "Original Foldername" #~ msgstr "Ursprungliga mappnamnet" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "T.ex. 119 eller 563 för SSL" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "Visa tider allmänt i AM/PM (påverkar inte schemaläggare)" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "Använd 12-timmarsklocka (AM/PM)" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "" #~ "Skicka automatiskt beräknade valideringsresultat för nedladdningar till " #~ "indexe." #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "" #~ "Förbättrad funktionalitet, inklusive betyg och extra statusinformation finns " #~ "tillgänglig när den är ansluten till OZnzb indexe." SABnzbd-2.3.2/po/main/zh_CN.po0000644000000000000000000044041513217005051014034 0ustar 00000000000000# Chinese (Simplified) translation for sabnzbd # Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2012. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-12-06 10:30+0000\n" "PO-Revision-Date: 2017-06-22 07:06+0000\n" "Last-Translator: Safihre \n" "Language-Team: Chinese (Simplified) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-12-07 05:31+0000\n" "X-Generator: Launchpad (build 18511)\n" #: SABnzbd.py [Error message] msgid "Failed to start web-interface" msgstr "web 界面启动失败" #: SABnzbd.py [Warning message] msgid "Cannot find web template: %s, trying standard template" msgstr "无法找到 web 模板: %s,正在尝试标准模板" #: SABnzbd.py [Warning message] msgid "" "SABYenc disabled: no correct version found! (Found v%s, expecting v%s)" msgstr "SABYenc 已禁用:未找到正确的版本!(找到 v%s,要求 v%s)" #: SABnzbd.py [Warning message] msgid "" "SABYenc module... NOT found! Expecting v%s - https://sabnzbd.org/sabyenc" msgstr "SABYenc 模块... 未找到!要求 v%s - https://sabnzbd.org/sabyenc" #: SABnzbd.py [Error message] msgid "_yenc module... NOT found!" msgstr "_yenc 模块... *未* 找到!" #: SABnzbd.py [Error message] msgid "par2 binary... NOT found!" msgstr "par2 可执行程序... *未* 找到!" #: SABnzbd.py [Error message] # SABnzbd.py [Error message] msgid "Verification and repair will not be possible." msgstr "" #: SABnzbd.py [Error message] msgid "MultiPar binary... NOT found!" msgstr "" #: SABnzbd.py [Warning message] msgid "Your UNRAR version is %s, we recommend version %s or higher.
" msgstr "您的 UNRAR 程序版本为 %s,我们建议使用 %s 或更高版本。
" #: SABnzbd.py [Error message] msgid "Downloads will not unpacked." msgstr "" #: SABnzbd.py [Error message] msgid "unrar binary... NOT found" msgstr "unrar 可执行程序... *未* 找到" #: SABnzbd.py msgid "unzip binary... NOT found!" msgstr "unzip 可执行程序... *未* 找到!" #: SABnzbd.py msgid "7za binary... NOT found!" msgstr "7za 可执行程序... *未*找到!" #: SABnzbd.py [Warning message] msgid "" "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external " "access" msgstr "请注意 0.0.0.0 主机名需要 IPv6 地址才能从外部访问" #: SABnzbd.py [Error message] msgid "HTTP and HTTPS ports cannot be the same" msgstr "HTTP 与 HTTPS 端口不能相同" #: SABnzbd.py [Warning message] msgid "" "SABnzbd was started with encoding %s, this should be UTF-8. Expect problems " "with Unicoded file and directory names in downloads." msgstr "SABnzbd 以 %s 编码启动了,正常应该是 UTF-8。会导致下载文件夹中统一标准编码的文件和文件夹名称出现问题。" #: SABnzbd.py [Warning message] msgid "Disabled HTTPS because of missing CERT and KEY files" msgstr "由于缺少 CERT 及 KEY 文件,已禁用 HTTPS" #: SABnzbd.py [Error message] msgid "Failed to start web-interface: " msgstr "无法启动 web 界面: " #: SABnzbd.py [Error message] msgid "Cannot reach the SABHelper service" msgstr "无法连接 SABHelper 服务" #: SABnzbd.py msgid "SABnzbd %s started" msgstr "SABnzbd %s 已启动" #: SABnzbd.py # sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Status page, table column header, actual message] msgid "Warning" msgstr "警告" #: SABnzbd.py # sabnzbd/notifier.py [Notification] msgid "Error" msgstr "错误" #: SABnzbd.py # sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/osxmenu.py # sabnzbd/wizard.py msgid "SABnzbd shutdown finished" msgstr "SABnzbd 关闭完成" #: sabnzbd/utils/servertests.py msgid "The hostname is not set." msgstr "主机名未设置。" #: sabnzbd/utils/servertests.py msgid "There are no connections set. Please set at least one connection." msgstr "未设置连接。请设置至少一个连接。" #: sabnzbd/utils/servertests.py msgid "Password masked in ******, please re-enter" msgstr "密码会以 ****** 显示,请重新输入" #: sabnzbd/utils/servertests.py msgid "Invalid server details" msgstr "服务器信息无效" #: sabnzbd/utils/servertests.py msgid "Timed out: Try enabling SSL or connecting on a different port." msgstr "超时: 请尝试启用 SSL 或连接其他端口。" #: sabnzbd/utils/servertests.py msgid "Timed out" msgstr "超时" #: sabnzbd/utils/servertests.py msgid "" "Unknown SSL protocol: Try disabling SSL or connecting on a different port." msgstr "未知的 SSL 协议:尝试禁用 SSL 或者连接不同的端口。" #: sabnzbd/utils/servertests.py msgid "Invalid server address." msgstr "服务器地址无效。" #: sabnzbd/utils/servertests.py msgid "Server quit during login sequence." msgstr "登录过程中服务器退出。" #: sabnzbd/utils/servertests.py msgid "Server requires username and password." msgstr "服务器需要用户名与密码。" #: sabnzbd/utils/servertests.py msgid "Connection Successful!" msgstr "连接成功!" #: sabnzbd/utils/servertests.py # sabnzbd/interface.py #: sabnzbd/newswrapper.py msgid "Authentication failed, check username/password." msgstr "身份认证失败,请检查用户名/密码。" #: sabnzbd/utils/servertests.py msgid "Too many connections, please pause downloading or try again later" msgstr "连接数过多,请先暂停下载或稍后再试" #: sabnzbd/utils/servertests.py msgid "Could not determine connection result (%s)" msgstr "无法判断连接结果 (%s)" #: sabnzbd/__init__.py [Warning message] msgid "Signal %s caught, saving and exiting..." msgstr "捕捉到 %s 信号,正在保存并退出..." #: sabnzbd/__init__.py [Error message] msgid "Fatal error at saving state" msgstr "保存状态时遇到致命错误" #: sabnzbd/__init__.py msgid "Trying to fetch NZB from %s" msgstr "正在尝试从 %s 装取 NZB" #: sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] # sabnzbd/__init__.py [Error message] msgid "Saving %s failed" msgstr "保存 %s 失败" #: sabnzbd/__init__.py [Error message] msgid "Cannot create temp file for %s" msgstr "无法为 %s 创建临时文件" #: sabnzbd/__init__.py [Warning message] # sabnzbd/__init__.py [Warning message] msgid "Trying to set status of non-existing server %s" msgstr "正在尝试设置不存在的服务器 %s 的状态" #: sabnzbd/__init__.py [Error message] msgid "Failure in tempfile.mkstemp" msgstr "tempfile.mkstemp 出错" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed" msgstr "加载 %s 失败" #: sabnzbd/__init__.py [Error message] msgid "Loading %s failed with error %s" msgstr "加载 %s 失败,错误 %s" #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py # sabnzbd/api.py #: sabnzbd/skintext.py msgid "Test Notification" msgstr "测试通知" #: sabnzbd/api.py msgid " Resolving address" msgstr " 正在解析地址" #: sabnzbd/api.py # sabnzbd/skintext.py [No value, used in dropdown menus] # sabnzbd/skintext.py [Job details page, select no files] msgid "None" msgstr "无" #: sabnzbd/api.py # sabnzbd/interface.py # sabnzbd/skintext.py [Default value, used in dropdown menus] msgid "Default" msgstr "默认" #: sabnzbd/api.py msgid "unknown" msgstr "未知" #: sabnzbd/api.py [Error message] msgid "Failed to compile regex for search term: %s" msgstr "为搜索关键词编译正则表达式失败: %s" #: sabnzbd/assembler.py [Warning message] msgid "Too little diskspace forcing PAUSE" msgstr "磁盘空间过低,强制 *暂停*" #: sabnzbd/assembler.py [Error message] msgid "Disk full! Forcing Pause" msgstr "磁盘已满! 强制暂停" #: sabnzbd/assembler.py [Error message] msgid "Disk error on creating file %s" msgstr "创建文件 %s 时磁盘出错" #: sabnzbd/assembler.py [Error message] msgid "Fatal error in Assembler" msgstr "Assembler 出现致命错误" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Paused job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "警告:\"%s\" 任务已暂停,因其包含加密 RAR 文件 (已尝试所有的密码,如果提供了的话)" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: Aborted job \"%s\" because of encrypted RAR file (if supplied, all " "passwords were tried)" msgstr "警告:\"%s\" 任务已终止,因其包含加密 RAR 文件 (已尝试所有的密码,如果提供了的话)" #: sabnzbd/assembler.py msgid "Aborted, encryption detected" msgstr "已中止,发现加密文件" #: sabnzbd/assembler.py [Warning message] msgid "" "WARNING: In \"%s\" unwanted extension in RAR file. Unwanted file is %s " msgstr "*警告*: RAR 文件“%s”中出现不需要的扩展名。不需要的文件名为 %s " #: sabnzbd/assembler.py msgid "Unwanted extension is in rar file %s" msgstr "rar 文件中出现不需要的扩展名 %s" #: sabnzbd/assembler.py msgid "Aborted, unwanted extension detected" msgstr "已中止,侦测到不需要的扩展名" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Paused job \"%s\" because of rating (%s)" msgstr "*警告*: 任务“%s”已暂停,由于评分过低 (%s)" #: sabnzbd/assembler.py [Warning message] msgid "WARNING: Aborted job \"%s\" because of rating (%s)" msgstr "*警告*: 任务“%s”已中止,由于评分过低 (%s)" #: sabnzbd/assembler.py msgid "Aborted, rating filter matched (%s)" msgstr "已中止,评分筛选器已命中 (%s)" #: sabnzbd/assembler.py # sabnzbd/assembler.py # sabnzbd/misc.py [Error message] msgid "%s missing" msgstr "缺少 %s" #: sabnzbd/assembler.py [Warning message] msgid "" "Job \"%s\" is probably encrypted due to RAR with same name inside this RAR" msgstr "任务 \"%s\" 可能受加密保护,RAR 文件中存在相同名称的 RAR 文件。" #: sabnzbd/assembler.py [Warning message] msgid "Job \"%s\" is probably encrypted: \"password\" in filename \"%s\"" msgstr "任务 \"%s\" 可能受加密保护:文件名 \"%s\" 中有 \"password\" 字符" #: sabnzbd/assembler.py msgid "video" msgstr "视频" #: sabnzbd/assembler.py msgid "audio" msgstr "音频" #: sabnzbd/assembler.py msgid "spam" msgstr "垃圾" #: sabnzbd/assembler.py msgid "passworded" msgstr "有密码" #: sabnzbd/assembler.py msgid "downvoted" msgstr "已减分" #: sabnzbd/assembler.py msgid "keywords" msgstr "关键词" #: sabnzbd/bpsmeter.py [Warning message] msgid "Quota spent, pausing downloading" msgstr "配额已耗尽,暂停下载" #: sabnzbd/cfg.py msgid "%s is not a valid email address" msgstr "%s 不是有效的电子邮箱地址" #: sabnzbd/cfg.py # sabnzbd/interface.py msgid "Server address required" msgstr "服务器地址必填" #: sabnzbd/config.py msgid "Cannot create %s folder %s" msgstr "无法创建 %s 文件夹 %s" #: sabnzbd/config.py [Error message] # sabnzbd/config.py [Error message] msgid "Cannot write to INI file %s" msgstr "无法写入 INI 文件 %s" #: sabnzbd/config.py [Error message] msgid "Cannot create backup file for %s" msgstr "无法为 %s 创建备份文件" #: sabnzbd/config.py [Error message] msgid "Incorrectly encoded password %s" msgstr "密码编码错误 %s" #: sabnzbd/config.py msgid "%s is not a correct octal value" msgstr "%s 不是有效的八进制值" #: sabnzbd/config.py msgid "UNC path \"%s\" not allowed here" msgstr "此处不允许使用 UNC 路径 \"%s\"" #: sabnzbd/config.py msgid "Error: Path length should be below %s." msgstr "错误: 路径长度应不超过 %s。" #: sabnzbd/config.py msgid "Error: Queue not empty, cannot change folder." msgstr "错误: 队列非空,无法变更文件夹。" #: sabnzbd/database.py [Error message] msgid "Cannot write to History database, check access rights!" msgstr "无法写入“历史记录”数据库,请检查访问权限!" #: sabnzbd/database.py [Error message] msgid "Damaged History database, created empty replacement" msgstr "“历史记录”数据库已损坏,已创建空数据库代替" #: sabnzbd/database.py [Error message] msgid "SQL Command Failed, see log" msgstr "SQL 命令执行失败,参见日志" #: sabnzbd/database.py [Error message] msgid "Failed to close database, see log" msgstr "无法关闭数据库,参见日志" #: sabnzbd/database.py [Error message] # sabnzbd/database.py [Error message] msgid "Invalid stage logging in history for %s" msgstr "%s 历史信息中 stage 日志无效" #: sabnzbd/decoder.py msgid "Decoding %s failed" msgstr "%s 解码失败" #: sabnzbd/decoder.py msgid "Decoder failure: Out of memory" msgstr "解码器失败:内存不足" #: sabnzbd/decoder.py msgid "Badly formed yEnc article in %s" msgstr "yEnc 文章格式错误:%s" #: sabnzbd/decoder.py msgid "Unknown Error while decoding %s" msgstr "解码 %s 时发生未知错误" #: sabnzbd/decoder.py msgid "UUencode detected, only yEnc encoding is supported [%s]" msgstr "检测到 UUencode,但是仅有 yEnc 编码受支持 [%s]" #: sabnzbd/decoder.py msgid "%s => missing from all servers, discarding" msgstr "%s => 所有服务器均缺失,正在舍弃" #: sabnzbd/directunpacker.py # sabnzbd/directunpacker.py #: sabnzbd/directunpacker.py # sabnzbd/skintext.py msgid "Direct Unpack" msgstr "" #: sabnzbd/directunpacker.py # sabnzbd/skintext.py [PP status] #: sabnzbd/skintext.py [History: job status] msgid "Completed" msgstr "完成" #: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py msgid "Unpacked %s files/folders in %s" msgstr "已解压 %s 个文件/文件夹,耗时 %s" #: sabnzbd/directunpacker.py [Warning message] msgid "Direct Unpack was automatically enabled." msgstr "" #: sabnzbd/directunpacker.py [Warning message] # sabnzbd/skintext.py msgid "" "Jobs will start unpacking during the downloading to reduce post-processing " "time. Only works for jobs that do not need repair." msgstr "" #: sabnzbd/dirscanner.py # sabnzbd/dirscanner.py # sabnzbd/dirscanner.py #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Warning message] # sabnzbd/rss.py [Warning message] msgid "Cannot read %s" msgstr "无法读取 %s" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error while adding %s, removing" msgstr "加载 %s 出错,正在移除" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Error removing %s" msgstr "移除 %s 时出错" #: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message] msgid "Cannot read Watched Folder %s" msgstr "无法读取监视文件夹 %s" #: sabnzbd/downloader.py msgid "Resuming" msgstr "恢复中" #: sabnzbd/downloader.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py [Priority pick list] #: sabnzbd/skintext.py msgid "Paused" msgstr "已暂停" #: sabnzbd/downloader.py [Warning message] # sabnzbd/interface.py [Warning message] # sabnzbd/skintext.py msgid "You must set a maximum bandwidth before you can set a bandwidth limit" msgstr "设置带宽限制前,您必须设置最大带宽值" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Server %s will be ignored for %s minutes" msgstr "服务器 %s 将被忽略 %s 分钟" #: sabnzbd/downloader.py [Error message] msgid "Failed to initialize %s@%s with reason: %s" msgstr "无法初始化 %s@%s,原因为: %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Too many connections to server %s" msgstr "服务器 %s 连接数过多" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Probable account sharing" msgstr "可能存在账号共享" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Error message] msgid "Failed login for server %s" msgstr "无法登录服务器 %s" #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] #: sabnzbd/downloader.py # sabnzbd/downloader.py [Warning message] msgid "Cannot connect to server %s [%s]" msgstr "无法连接到服务器 %s [%s]" #: sabnzbd/downloader.py [Error message] msgid "Connecting %s@%s failed, message=%s" msgstr "连接 %s@%s 失败,消息=%s" #: sabnzbd/downloader.py # sabnzbd/downloader.py msgid "Server %s requires user/password" msgstr "服务器 %s 需要用户/密码" #: sabnzbd/downloader.py [Error message] msgid "Suspect error in downloader" msgstr "下载器疑似错误" #: sabnzbd/downloader.py # sabnzbd/skintext.py msgid "Shutting down" msgstr "正在关闭" #: sabnzbd/emailer.py # sabnzbd/emailer.py msgid "Failed to connect to mail server" msgstr "无法连接到邮件服务器" #: sabnzbd/emailer.py msgid "Failed to initiate TLS connection" msgstr "无法发起 TLS 连接" #: sabnzbd/emailer.py msgid "The server didn't reply properly to the helo greeting" msgstr "服务器未正确回复 helo 问候" #: sabnzbd/emailer.py msgid "Failed to authenticate to mail server" msgstr "无法在邮件服务器上验证身份" #: sabnzbd/emailer.py msgid "No suitable authentication method was found" msgstr "未找到合适的身份验证方法" #: sabnzbd/emailer.py msgid "Unknown authentication failure in mail server" msgstr "邮件服务器出现未知身份验证错误" #: sabnzbd/emailer.py msgid "Failed to send e-mail" msgstr "无法发送 e-mail" #: sabnzbd/emailer.py msgid "Failed to close mail connection" msgstr "无法关闭邮件连接" #: sabnzbd/emailer.py msgid "Email succeeded" msgstr "成功发送电子邮件" #: sabnzbd/emailer.py # sabnzbd/notifier.py # sabnzbd/notifier.py #: sabnzbd/notifier.py # sabnzbd/notifier.py # sabnzbd/rating.py #: sabnzbd/rating.py msgid "Cannot send, missing required data" msgstr "无法发送,缺少必要的数据" #: sabnzbd/emailer.py [Error message] msgid "Cannot find email templates in %s" msgstr "无法找到 email 模板:%s" #: sabnzbd/emailer.py msgid "No recipients given, no email sent" msgstr "未给定收件人,电子邮件未发出" #: sabnzbd/emailer.py msgid "Invalid encoding of email template %s" msgstr "email 模板 %s 编码无效" #: sabnzbd/emailer.py msgid "No email templates found" msgstr "未找到 email 模板" #: sabnzbd/emailer.py msgid "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd reports Disk Full\n" "\n" "Hi,\n" "\n" "SABnzbd has stopped downloading, because the disk is almost full.\n" "Please make room and resume SABnzbd manually.\n" "\n" msgstr "" "To: %s\n" "From: %s\n" "Date: %s\n" "Subject: SABnzbd 报告磁盘已满\n" "\n" "Hi,\n" "\n" "由于磁盘几乎已满,SABnzbd 已停止下载。\n" "请腾出空间再手动让 SABnzbd 续传。\n" "\n" #: sabnzbd/interface.py msgid "Warning: LOCALHOST is ambiguous, use numerical IP-address." msgstr "警告: LOCALHOST 太含糊,请使用数字 IP 地址。" #: sabnzbd/interface.py msgid "Server address \"%s:%s\" is not valid." msgstr "服务器地址 \"%s:%s\" 无效。" #: sabnzbd/interface.py msgid "User logged in to the web interface" msgstr "用户已在 web 界面登录" #: sabnzbd/interface.py # sabnzbd/notifier.py [Notification] msgid "User logged in" msgstr "用户已登录" #: sabnzbd/interface.py [Warning message] msgid "Missing Session key" msgstr "缺会话 key" #: sabnzbd/interface.py msgid "Error: Session Key Required" msgstr "错误: 需要会话 Key" #: sabnzbd/interface.py [Warning message] # sabnzbd/interface.py msgid "Error: Session Key Incorrect" msgstr "错误: 会话 Key 不正确" #: sabnzbd/interface.py msgid "" "API Key missing, please enter the api key from Config->General into your 3rd " "party program:" msgstr "缺 API Key,请将“配置”->“常规”中的 api key 输入到第三方程序中:" #: sabnzbd/interface.py msgid "" "API Key incorrect, Use the api key from Config->General in your 3rd party " "program:" msgstr "API Key 不正确,请在第三方程序中使用“配置”->“常规”中的 api key:" #: sabnzbd/interface.py msgid "" "Authentication missing, please enter username/password from Config->General " "into your 3rd party program:" msgstr "缺身份认证信息,请在第三方程序中输入“配置”->“常规”中的用户名/密码:" #: sabnzbd/interface.py [Warning message] msgid "" "Try our new skin Glitter! Fresh new design that is optimized for desktop and " "mobile devices. Go to Config -> General to change your skin." msgstr "请尝试我们的新皮肤“Glitter”! 为桌面及移动设备优化的全新设计。请到“配置”->“常规”更改皮肤。" #: sabnzbd/interface.py msgid "Unsuccessful login attempt from %s" msgstr "%s 中有失败的登陆请求" #: sabnzbd/interface.py # sabnzbd/skintext.py [Bytes (used as postfix, as in "GB", "TB")] msgid "B" msgstr "B" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "" " 
SABnzbd shutdown finished.
Wait for about 5 second and then " "click the button below.

Refresh
" msgstr "" " 
SABnzbd 关闭完成。
请等待约 5 秒后点击下面的按钮。

刷新
" #: sabnzbd/interface.py # sabnzbd/skintext.py [Config->RSS, tab header] msgid "Feed" msgstr "Feed" #: sabnzbd/interface.py msgid "Daily" msgstr "每天" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Monday" msgstr "周一" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Tuesday" msgstr "周二" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Wednesday" msgstr "周三" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Thursday" msgstr "周四" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Friday" msgstr "周五" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Saturday" msgstr "周六" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "Sunday" msgstr "周日" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "off" msgstr "关" #: sabnzbd/interface.py msgid "Undefined server!" msgstr "未定义服务器!" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Incorrect parameter" msgstr "参数不正确" #: sabnzbd/interface.py msgid "" "Category folder cannot be a subfolder of the Temporary Download Folder." msgstr "" #: sabnzbd/interface.py # sabnzbd/interface.py msgid "Back" msgstr "返回" #: sabnzbd/interface.py # sabnzbd/skintext.py msgid "ERROR:" msgstr "错误:" #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py # sabnzbd/interface.py #: sabnzbd/interface.py msgid "Incorrect value for %s: %s" msgstr "%s 值不正确: %s" #: sabnzbd/misc.py msgid "d" msgstr "天" #: sabnzbd/misc.py msgid "h" msgstr "小时" #: sabnzbd/misc.py msgid "m" msgstr "分钟" #: sabnzbd/misc.py [Error message] # sabnzbd/sorting.py [Error message] msgid "Cannot create directory %s" msgstr "无法创建目录 %s" #: sabnzbd/misc.py [Error message] msgid "%s directory: %s error accessing" msgstr "%s 目录: %s 访问出错" #: sabnzbd/misc.py [Error message] msgid "Failed making (%s)" msgstr "创建失败 (%s)" #: sabnzbd/misc.py [Error message] # sabnzbd/postproc.py msgid "Failed moving %s to %s" msgstr "将 %s 移动到 %s 失败" #: sabnzbd/misc.py [Error message] msgid "Error creating SSL key and certificate" msgstr "创建 SSL key 及证书出错" #: sabnzbd/misc.py [Warning message] msgid "" "Your password file contains more than 30 passwords, testing all these " "passwords takes a lot of time. Try to only list useful passwords." msgstr "" #: sabnzbd/misc.py [Error message] msgid "Cannot change permissions of %s" msgstr "无法更改 %s 的权限" #: sabnzbd/newsunpack.py # sabnzbd/postproc.py msgid "Running script" msgstr "正在执行脚本" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/postproc.py msgid "PostProcessing was aborted (%s)" msgstr "后期处理已中止 (%s)" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "script"] # sabnzbd/skintext.py #: sabnzbd/skintext.py [Notification Script settings] msgid "Script" msgstr "脚本" #: sabnzbd/newsunpack.py [Warning message] msgid "Unpack nesting too deep [%s]" msgstr "解压嵌套层级过深 [%s]" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Joining" msgstr "正在合并" #: sabnzbd/newsunpack.py msgid "Incomplete sequence of joinable files" msgstr "可合并的文件队列不完整" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "File join of %s failed" msgstr "%s 文件合并失败" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while joining files" msgstr "[%s] \"%s\" 合并文件时出错" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running file_join on %s" msgstr "\"%s\" 对 %s 运行 file_join 时出错" #: sabnzbd/newsunpack.py msgid "[%s] Joined %s files" msgstr "[%s] 已合并 %s 个文件" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, %s" msgstr "解压失败,%s" #: sabnzbd/newsunpack.py msgid "[%s] Error \"%s\" while unpacking RAR files" msgstr "[%s] \"%s\" 解压 RAR 文件时出错" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running rar_unpack on %s" msgstr "出现错误 \"%s\",正对 %s 执行 rar_unpack 操作" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py [Warning message] #: sabnzbd/newsunpack.py [Warning message] msgid "Deleting %s failed!" msgstr "删除 %s 失败!" #: sabnzbd/newsunpack.py msgid "Trying unrar with password \"%s\"" msgstr "正在尝试 unrar,使用密码 \"%s\"" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, archive requires a password" msgstr "解压失败,压缩文件需要密码" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking" msgstr "正在解压" #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP phase "unpack"] msgid "Unpack" msgstr "解压" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, unable to find %s" msgstr "解压失败,找不到 %s" #: sabnzbd/newsunpack.py [Warning message] msgid "ERROR: unable to find \"%s\"" msgstr "错误: 无法找到 \"%s\"" #: sabnzbd/newsunpack.py msgid "Unpacking failed, CRC error" msgstr "解压失败,CRC 错误" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py [Warning message] msgid "ERROR: CRC failed in \"%s\"" msgstr "错误: \"%s\" CRC 失败" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, file too large for filesystem (FAT?)" msgstr "解压失败,文件太大文件系统不支持 (FAT?)" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: File too large for filesystem (%s)" msgstr "错误:文件太大文件系统不支持 (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, write error or disk is full?" msgstr "解压失败,写入出错或磁盘已满?" #: sabnzbd/newsunpack.py [Error message] # sabnzbd/newsunpack.py [Error message] msgid "ERROR: write error (%s)" msgstr "错误: 写入出错 (%s)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unpacking failed, path is too long" msgstr "解压失败,路径过长" #: sabnzbd/newsunpack.py [Error message] msgid "ERROR: path too long (%s)" msgstr "*错误*: 路径过长 (%s)" #: sabnzbd/newsunpack.py msgid "Unpacking failed, see log" msgstr "解压失败,参见日志" #: sabnzbd/newsunpack.py [Warning message] # sabnzbd/newsunpack.py msgid "ERROR: %s" msgstr "错误: %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Unusable RAR file" msgstr "无法使用的 RAR 文件" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Corrupt RAR file" msgstr "损坏的 RAR 文件" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "%s files in %s" msgstr "%s 个文件,耗时 %s" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running unzip() on %s" msgstr "\"%s\" 对 %s 执行 unzip() 时出错" #: sabnzbd/newsunpack.py msgid "Trying 7zip with password \"%s\"" msgstr "正在尝试 7zip,密码 \"%s\"" #: sabnzbd/newsunpack.py msgid "7ZIP set \"%s\" is incomplete, cannot unpack" msgstr "7ZIP 分卷组 \"%s\" 不完整,无法解压" #: sabnzbd/newsunpack.py msgid "Could not unpack %s" msgstr "无法解压 %s" #: sabnzbd/newsunpack.py msgid "Quick Checking" msgstr "快速检查" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/skintext.py [PP phase "repair"] # sabnzbd/skintext.py msgid "Repair" msgstr "修复" #: sabnzbd/newsunpack.py msgid "[%s] Quick Check OK" msgstr "[%s] 快速检查 OK" #: sabnzbd/newsunpack.py msgid "Starting Repair" msgstr "正在开始修复" #: sabnzbd/newsunpack.py [Warning message] msgid "Par verify failed on %s, while QuickCheck succeeded!" msgstr "Par 验证失败:%s,但快速检查成功!" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing failed, %s" msgstr "修复失败,%s" #: sabnzbd/newsunpack.py [Error message] msgid "Error %s while running par2_repair on set %s" msgstr "%s 对集合 %s 执行 par2_repair 时出错" #: sabnzbd/newsunpack.py [Error message] msgid "Error \"%s\" while running par2_repair on set %s" msgstr "\"%s\" 对集合 %s 执行 par2_repair 时出错" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "[%s] PAR2 received incorrect options, check your Config->Switches settings" msgstr "[%s] PAR2 收到的选项不正确,请检查您的“配置”->“参数”设置" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, all files correct" msgstr "[%s] 验证耗时 %s,所有文件均完好无损" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Verified in %s, repair is required" msgstr "[%s] 验证耗时 %s,需要修复" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "" "Invalid par2 files or invalid PAR2 parameters, cannot verify or repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching %s blocks..." msgstr "正在装取 %s 块..." #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Fetching" msgstr "正在装取" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repair failed, not enough repair blocks (%s short)" msgstr "修复失败,修复块不足 (缺 %s 块)" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Repairing" msgstr "正在修复" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "[%s] Repaired in %s" msgstr "[%s] 已修复,耗时 %s" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py msgid "Verifying repair" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/notifier.py [Notification] msgid "Disk full" msgstr "磁盘空间已满" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Verifying" msgstr "正在验证" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py msgid "Checking extra files" msgstr "" #: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py #: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status] msgid "Checking" msgstr "正在检查" #: sabnzbd/newsunpack.py [Error message] msgid "Python script \"%s\" does not have execute (+x) permission set" msgstr "Python 脚本 \"%s\" 不具有执行 (+x) 权限" #: sabnzbd/newswrapper.py msgid "This server does not allow SSL on this port" msgstr "该服务器不允许在该端口使用 SSL" #: sabnzbd/newswrapper.py msgid "" "Certificate hostname mismatch: the server hostname is not listed in the " "certificate. This is a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Certificate not valid. This is most probably a server issue." msgstr "" #: sabnzbd/newswrapper.py msgid "Server %s uses an untrusted certificate [%s]" msgstr "%s 服务器使用了不受信任的证书 [%s]" #: sabnzbd/newswrapper.py # sabnzbd/skintext.py [Main menu item] msgid "Wiki" msgstr "Wiki" #: sabnzbd/notifier.py [Notification] msgid "Startup/Shutdown" msgstr "启动/关闭" #: sabnzbd/notifier.py [Notification] # sabnzbd/skintext.py [Config->RSS after adding to queue] msgid "Added NZB" msgstr "已添加 NZB" #: sabnzbd/notifier.py msgid "Post-processing started" msgstr "后期处理已开始" #: sabnzbd/notifier.py [Notification] msgid "Job finished" msgstr "任务已完成" #: sabnzbd/notifier.py [Notification] msgid "Job failed" msgstr "任务失败" #: sabnzbd/notifier.py [Notification] msgid "Queue finished" msgstr "队列已完成" #: sabnzbd/notifier.py [Notification] msgid "Other Messages" msgstr "其他信息" #: sabnzbd/notifier.py # sabnzbd/skintext.py msgid "Not available" msgstr "不可用" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send Prowl message" msgstr "无法发送 Prowl 消息" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushover (%s): %s" msgstr "Pushover 响应异常 (%s): %s" #: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushover message" msgstr "无法发送 pushover 信息" #: sabnzbd/notifier.py [Error message] msgid "Bad response from Pushbullet (%s): %s" msgstr "Pushbullet 响应异常 (%s): %s" #: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py msgid "Failed to send pushbullet message" msgstr "无法发送 pushbullet 信息" #: sabnzbd/notifier.py [Error message] # sabnzbd/notifier.py msgid "Script returned exit code %s and output \"%s\"" msgstr "脚本返回退出代码 %s 及输出内容 \"%s\"" #: sabnzbd/notifier.py msgid "Notification script \"%s\" does not exist" msgstr "通知脚本 \"%s\" 不存在" #: sabnzbd/notifier.py # sabnzbd/notifier.py msgid "Failed to send Windows notification" msgstr "无法发送 Windows 通知" #: sabnzbd/nzbqueue.py [Warning message] # sabnzbd/postproc.py [Warning message] msgid "Old queue detected, use Status->Repair to convert the queue" msgstr "侦测到旧版队列,请使用“状态”→“修复”转换队列" #: sabnzbd/nzbqueue.py [Error message] msgid "Incompatible queuefile found, cannot proceed" msgstr "发现不兼容的队列文件,无法继续处理" #: sabnzbd/nzbqueue.py [Error message] msgid "Error loading %s, corrupt file detected" msgstr "无法加载 %s,侦测到损坏文件" #: sabnzbd/nzbqueue.py [Error message] msgid "Failed to restart NZB after pre-check (%s)" msgstr "预先检查后无法重新开始下载 NZB (%s)" #: sabnzbd/nzbqueue.py msgid "NZB added to queue" msgstr "NZB 已添加到队列" #: sabnzbd/nzbqueue.py [Warning message] msgid "%s -> Unknown encoding" msgstr "%s -> 未知编码" #: sabnzbd/nzbstuff.py [Warning message] msgid "File %s is empty, skipping" msgstr "文件 %s 为空,正在跳过" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failed to import %s files from %s" msgstr "导入 %s 文件失败,来自 %s" #: sabnzbd/nzbstuff.py [Warning message] msgid "Incomplete NZB file %s" msgstr "NZB 文件 %s 不完整" #: sabnzbd/nzbstuff.py [Warning message] # sabnzbd/nzbstuff.py [Warning message] msgid "Invalid NZB file %s, skipping (reason=%s, line=%s)" msgstr "无效 NZB 文件 %s,正在跳过 (原因=%s, 行=%s)" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py msgid "Empty NZB file %s" msgstr "空 NZB 文件 %s" #: sabnzbd/nzbstuff.py msgid "Pre-queue script marked job as failed" msgstr "预队列脚本将任务标记为失败的" #: sabnzbd/nzbstuff.py [Warning message] msgid "Ignoring duplicate NZB \"%s\"" msgstr "正在忽略重复 NZB \"%s\"" #: sabnzbd/nzbstuff.py [Warning message] msgid "Failing duplicate NZB \"%s\"" msgstr "失败于重复的 NZB 文件 \"%s\"" #: sabnzbd/nzbstuff.py # sabnzbd/nzbstuff.py [Warning message] msgid "Duplicate NZB" msgstr "重复的 NZB 文件" #: sabnzbd/nzbstuff.py [Warning message] msgid "Pausing duplicate NZB \"%s\"" msgstr "正在暂停重复 NZB \"%s\"" #: sabnzbd/nzbstuff.py msgid "Aborted, cannot be completed" msgstr "已中止,无法完成" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "DUPLICATE" msgstr "*重复*" #: sabnzbd/nzbstuff.py [Queue indicator for encrypted job] # sabnzbd/skintext.py msgid "ENCRYPTED" msgstr "*加密*" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "TOO LARGE" msgstr "*太大*" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "INCOMPLETE" msgstr "*不完整*" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "UNWANTED" msgstr "不需要" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "FILTERED" msgstr "已过滤" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py msgid "WAIT %s sec" msgstr "*等待* %s 秒" #: sabnzbd/nzbstuff.py msgid "PROPAGATING %s min" msgstr "传播延迟生效,等待 %s 分钟" #: sabnzbd/nzbstuff.py msgid "Downloaded in %s at an average of %sB/s" msgstr "已下载,耗时 %s,平均速度 %sB/s" #: sabnzbd/nzbstuff.py # sabnzbd/skintext.py [Job details page, file age column header] # sabnzbd/skintext.py msgid "Age" msgstr "发布时间" #: sabnzbd/nzbstuff.py msgid "%s articles were malformed" msgstr "%s 篇文章损坏" #: sabnzbd/nzbstuff.py msgid "%s articles were missing" msgstr "%s 篇文章缺失" #: sabnzbd/nzbstuff.py msgid "%s articles had non-matching duplicates" msgstr "%s 篇文章存在未匹配的重复" #: sabnzbd/nzbstuff.py msgid "%s articles were removed" msgstr "已移除 %s 篇文章" #: sabnzbd/nzbstuff.py [Error message] msgid "Error importing %s" msgstr "导入 %s 出错" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/skintext.py [Footer: indicator of warnings] # sabnzbd/skintext.py msgid "Warnings" msgstr "警告信息" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Idle" msgstr "空闲" #: sabnzbd/osxmenu.py msgid "Configuration" msgstr "配置" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Queue" msgstr "队列" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Queue page button] msgid "Purge Queue" msgstr "清空队列" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [Main menu item] msgid "History" msgstr "历史" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [History page button] # sabnzbd/skintext.py msgid "Purge History" msgstr "清空历史" #: sabnzbd/osxmenu.py msgid "Limit Speed" msgstr "限速" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Pause downloading] # sabnzbd/skintext.py [Four way switch for duplicates] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Pause" msgstr "暂停" #: sabnzbd/osxmenu.py msgid "min." msgstr "分钟" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Resume downloading] # sabnzbd/skintext.py [Config->Scheduling] msgid "Resume" msgstr "续传" #: sabnzbd/osxmenu.py # sabnzbd/skintext.py [#: Config->Scheduler] msgid "Scan watched folder" msgstr "扫描监视文件夹" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Read all RSS feeds" msgstr "读取所有 RSS feed" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Complete Folder" msgstr "完成文件夹" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Incomplete Folder" msgstr "未完成文件夹" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Troubleshoot" msgstr "疑难解决" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/sabtray.py #: sabnzbd/sabtraylinux.py # sabnzbd/sabtraylinux.py #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py # sabnzbd/skintext.py [Config->Scheduling] msgid "Restart" msgstr "重启" #: sabnzbd/osxmenu.py # sabnzbd/sabtray.py msgid "Restart without login" msgstr "清除登录身份凭据设置并重新启动" #: sabnzbd/osxmenu.py msgid "Quit" msgstr "退出" #: sabnzbd/osxmenu.py msgid "Queue First 10 Items" msgstr "将前十项加入队列" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py msgid "Empty" msgstr "清空" #: sabnzbd/osxmenu.py msgid "History Last 10 Items" msgstr "最近十条历史记录" #: sabnzbd/osxmenu.py msgid "New release available" msgstr "新版本可用" #: sabnzbd/osxmenu.py msgid "Go to wizard" msgstr "转到向导" #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py # sabnzbd/osxmenu.py # sabnzbd/osxmenu.py #: sabnzbd/osxmenu.py msgid "Stopping..." msgstr "正在停止..." #: sabnzbd/panic.py msgid "Problem with" msgstr "问题" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a free tcp/ip port for its internal web server.
\n" " Port %s on %s was tried , but it is not available.
\n" " Some other software uses the port or SABnzbd is already running.
\n" "
\n" " Please restart SABnzbd with a different port number." msgstr "" "\n" " SABnzbd 的内部 web 服务器需要一个空闲的 tcp/ip 端口。
\n" " 已尝试端口 %s(位于 %s),但不可用。
\n" " 有其他软件占用了该端口,或者 SABnzbd 已经在运行,
\n" "
\n" " 请使用其他端口号重启 SABnzbd。" #: sabnzbd/panic.py msgid "" "If you get this error message again, please try a different number.
" msgstr "如果您再次收到本错误信息,请尝试其他数字。
" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd needs a valid host address for its internal web server.
\n" " You have specified an invalid address.
\n" " Safe values are localhost and 0.0.0.0
\n" "
\n" " Please restart SABnzbd with a proper host address." msgstr "" "\n" " SABnzbd 的内部 web 服务器需要有效的主机地址。
\n" " 您指定的地址无效。
\n" " 安全的值有 localhost 与 0.0.0.0
\n" "
\n" " 请使用适当的主机地址重启 SABnzbd。" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected saved data from an other SABnzbd version
\n" " but cannot re-use the data of the other program.

\n" " You may want to finish your queue first with the other program.

\n" " After that, start this program with the \"--clean\" option.
\n" " This will erase the current queue and history!
\n" " SABnzbd read the file \"%s\"." msgstr "" "\n" " SABnzbd 侦测到其他 SABnzbd 版本已保存的数据
\n" " 但无法重新使用其他程序的数据。

\n" " 您可能需要先完成其他程序的队列。

\n" " 之后再使用 \"--clean\" 选项启动本程序。
\n" " 该选项将清除当前队列及历史!
\n" " SABnzbd 读取到的文件是 \"%s\"。" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd cannot find its web interface files in %s.
\n" " Please install the program again.
\n" "
\n" msgstr "" "\n" " SABnzbd 无法找到位于 %s 的 web 界面文件。
\n" " 请重新安装本程序。
\n" "
\n" #: sabnzbd/panic.py msgid "SABnzbd detected a fatal error:" msgstr "SABnzbd 侦测到致命错误:" #: sabnzbd/panic.py msgid "" "\n" " SABnzbd detected that the file sqlite3.dll is missing.

\n" " Some poorly designed virus-scanners remove this file.
\n" " Please check your virus-scanner, try to re-install SABnzbd and complain " "to your virus-scanner vendor.
\n" "
\n" msgstr "" "\n" " SABnzbd 侦测发现缺少 sqlite3.dll 文件。

\n" " 一些很差劲的病毒扫描程序会移除此文件。
\n" " 请检查您的病毒扫描程序,尝试重新安装 SABnzbd 并向病毒扫描程序厂商反映。
\n" "
\n" #: sabnzbd/panic.py msgid "Press Startkey+R and type the line (example):" msgstr "请按 开始菜单键+R 并输入下面一行命令 (例):" #: sabnzbd/panic.py msgid "Open a Terminal window and type the line (example):" msgstr "请打开“终端”窗口并输入下面一行命令 (例):" #: sabnzbd/panic.py msgid "Program did not start!" msgstr "程序未启动!" #: sabnzbd/panic.py msgid "" "Unable to bind to port %s on %s. Some other software uses the port or " "SABnzbd is already running." msgstr "绑定端口 %s 在 %s 上失败。其它的程序正在使用此端口或者说 SABnzbd 正在运行。" #: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py msgid "Fatal error" msgstr "致命错误" #: sabnzbd/panic.py [Warning message] msgid "Cannot launch the browser, probably not found" msgstr "无法启动浏览器,可能未找到" #: sabnzbd/panic.py msgid "Access denied" msgstr "访问被拒绝" #: sabnzbd/panic.py msgid "Error %s: You need to provide a valid username and password." msgstr "错误 %s: 您需要提供有效的用户名与密码。" #: sabnzbd/postproc.py [Warning message] msgid "" "Completed Download Folder %s is on FAT file system, limiting maximum file " "size to 4GB" msgstr "已完成文件夹 %s 位于 FAT 文件系统上,这样会有最大文件为 4GB 的限制。" #: sabnzbd/postproc.py [Warning message] msgid "" "Module subprocessww missing. Expect problems with Unicoded file and " "directory names in downloads." msgstr "" #: sabnzbd/postproc.py msgid "Download might fail, only %s of required %s available" msgstr "下载可能会失败,只有 %s 块 (需要 %s) 可用" #: sabnzbd/postproc.py msgid "Download failed - Not on your server(s)" msgstr "下载失败 - 不在该服务器上" #: sabnzbd/postproc.py msgid "No post-processing because of failed verification" msgstr "由于验证失败,未进行后期处理" #: sabnzbd/postproc.py msgid "Moving" msgstr "正在移动" #: sabnzbd/postproc.py msgid "Sent %s to queue" msgstr "已将 %s 发送到队列" #: sabnzbd/postproc.py [Error message] msgid "Error renaming \"%s\" to \"%s\"" msgstr "将 \"%s\" 重命名为 \"%s\" 出错" #: sabnzbd/postproc.py msgid "Failed to move files" msgstr "移动文件失败" #: sabnzbd/postproc.py msgid "Running user script %s" msgstr "正在执行用户脚本 %s" #: sabnzbd/postproc.py msgid "Ran %s" msgstr "执行 %s" #: sabnzbd/postproc.py msgid "Script exit code is %s" msgstr "脚本退出代码为 %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py msgid "More" msgstr "更多" #: sabnzbd/postproc.py [Error message] msgid "Post Processing Failed for %s (%s)" msgstr "后期处理失败:%s (%s)" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py msgid "see logfile" msgstr "查看日志文件" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Download Failed" msgstr "下载失败" #: sabnzbd/postproc.py [Error message] msgid "Cleanup of %s failed." msgstr "%s 清理失败。" #: sabnzbd/postproc.py [Error message] msgid "Error removing workdir (%s)" msgstr "移除工作目录出错 (%s)" #: sabnzbd/postproc.py msgid "Download Completed" msgstr "下载完成" #: sabnzbd/postproc.py [Error message] msgid "Cannot create final folder %s" msgstr "无法创建最终文件夹 %s" #: sabnzbd/postproc.py msgid "Post-processing" msgstr "后期处理" #: sabnzbd/postproc.py msgid "[%s] No par2 sets" msgstr "[%s] 无 par2 集合" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying SFV verification" msgstr "正在尝试 SFV 验证" #: sabnzbd/postproc.py msgid "Some files failed to verify against \"%s\"" msgstr "部分文件的验证结果与 \"%s\" 不符" #: sabnzbd/postproc.py msgid "Verified successfully using SFV files" msgstr "成功使用 SFV 文件验证" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "Trying RAR-based verification" msgstr "正在尝试基于 RAR 的验证" #: sabnzbd/postproc.py # sabnzbd/postproc.py msgid "[%s] RAR-based verification failed: %s" msgstr "[%s] 基于 RAR 的验证失败: %s" #: sabnzbd/postproc.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Passworded" msgstr "有密码" #: sabnzbd/postproc.py msgid "RAR files verified successfully" msgstr "RAR 文件验证成功" #: sabnzbd/postproc.py msgid "RAR files failed to verify" msgstr "RAR 文件验证失败" #: sabnzbd/postproc.py [Error message] # sabnzbd/postproc.py [Error message] msgid "Removing %s failed" msgstr "移除 %s 失败" #: sabnzbd/powersup.py [Error message] msgid "Failed to hibernate system" msgstr "系统休眠失败" #: sabnzbd/powersup.py [Error message] # sabnzbd/powersup.py [Error message] msgid "Failed to standby system" msgstr "系统待机失败" #: sabnzbd/powersup.py [Error message] msgid "Error while shutting down system" msgstr "关闭系统时出错" #: sabnzbd/rating.py [Warning message] msgid "Indexer id (%s) not found for ratings file" msgstr "评分文件的索引器 id (%s) 未找到" #: sabnzbd/rating.py # sabnzbd/skintext.py [Address of Growl server] msgid "Server address" msgstr "服务器地址" #: sabnzbd/rating.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "API Key" msgstr "API Key" #: sabnzbd/rating.py # sabnzbd/skintext.py msgid "" "This key provides identity to indexer. Check your profile on the indexer's " "website." msgstr "这个密钥用来向服务器表明身份。查看您在索引网站上的个人档案。" #: sabnzbd/rss.py [Error message] # sabnzbd/rss.py msgid "Incorrect RSS feed description \"%s\"" msgstr "RSS feed 描述不正确 \"%s\"" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Failed to retrieve RSS from %s: %s" msgstr "无法检索 %s 的 RSS: %s" #: sabnzbd/rss.py msgid "Do not have valid authentication for feed %s" msgstr "feed %s 无有效的身份认证凭据" #: sabnzbd/rss.py msgid "Server side error (server code %s); could not get %s on %s" msgstr "服务器端错误 (服务器代码 %s);无法获取 %s (服务器 %s)" #: sabnzbd/rss.py # sabnzbd/urlgrabber.py msgid "Server %s uses an untrusted HTTPS certificate" msgstr "服务器 %s 使用的 HTTPS 证书不受信任" #: sabnzbd/rss.py msgid "RSS Feed %s was empty" msgstr "RSS Feed %s 为空" #: sabnzbd/rss.py # sabnzbd/rss.py msgid "Incompatible feed" msgstr "feed 不兼容" #: sabnzbd/rss.py [Warning message] msgid "Empty RSS entry found (%s)" msgstr "发现空的 RSS 条目 (%s)" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Show interface" msgstr "显示界面" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py msgid "Open complete folder" msgstr "打开完成文件夹" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Shutdown SABnzbd] #: sabnzbd/skintext.py [Config->Scheduling] msgid "Shutdown" msgstr "关闭" #: sabnzbd/sabtray.py # sabnzbd/sabtraylinux.py # sabnzbd/skintext.py msgid "Remaining" msgstr "剩余" #: sabnzbd/sabtraylinux.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Add NZB" msgstr "添加 NZB" #: sabnzbd/scheduler.py [Warning message] msgid "Bad schedule %s at %s:%s" msgstr "定时任务 %s 存在问题,时间为 %s:%s" #: sabnzbd/scheduler.py [Warning message] msgid "Unknown action: %s" msgstr "未知操作: %s" #: sabnzbd/scheduler.py [Warning message] # sabnzbd/scheduler.py [Warning message] msgid "Schedule for non-existing server %s" msgstr "定时任务的服务器不存在 %s" #: sabnzbd/skintext.py [Queue status "download"] # sabnzbd/skintext.py [Post processing pick list] # sabnzbd/skintext.py [Config->RSS button "download item"] msgid "Download" msgstr "下载" #: sabnzbd/skintext.py [PP phase "filejoin"] msgid "Join files" msgstr "合并文件" #: sabnzbd/skintext.py [PP Source of the NZB (path or URL)] # sabnzbd/skintext.py [Where to find the SABnzbd sourcecode] msgid "Source" msgstr "来源" #: sabnzbd/skintext.py [PP Distribution over servers] # sabnzbd/skintext.py [Main menu item] msgid "Servers" msgstr "服务器" #: sabnzbd/skintext.py [PP Failure message] msgid "Failure" msgstr "失败" #: sabnzbd/skintext.py [PP status] # sabnzbd/skintext.py msgid "Failed" msgstr "失败" #: sabnzbd/skintext.py [Queue and PP status] msgid "Waiting" msgstr "等待" #: sabnzbd/skintext.py [PP status] msgid "Repairing..." msgstr "正在修复..." #: sabnzbd/skintext.py [PP status] msgid "Extracting..." msgstr "正在提取..." #: sabnzbd/skintext.py [PP status] msgid "Moving..." msgstr "正在移动..." #: sabnzbd/skintext.py [PP status] msgid "Running script..." msgstr "正在执行脚本..." #: sabnzbd/skintext.py [PP status] msgid "Fetching extra blocks..." msgstr "正在装取额外块..." #: sabnzbd/skintext.py [PP status] msgid "Quick Check..." msgstr "快速检查..." #: sabnzbd/skintext.py [PP status] msgid "Verifying..." msgstr "正在验证..." #: sabnzbd/skintext.py [Pseudo-PP status, in reality used for Queue-status] # sabnzbd/skintext.py msgid "Downloading" msgstr "正在下载" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Propagation delay" msgstr "传播延迟" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Frequency" msgstr "频率" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Job details page, section header] msgid "Action" msgstr "动作" #: sabnzbd/skintext.py [#: Config->Scheduler] # sabnzbd/skintext.py [Config->Scheduling] msgid "Arguments" msgstr "参数" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Task" msgstr "任务" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "disable server" msgstr "禁用服务器" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "enable server" msgstr "启用服务器" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Speedlimit" msgstr "限速" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause All" msgstr "全部暂停" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Pause post-processing" msgstr "暂停后期处理" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Resume post-processing" msgstr "继续后期处理" #: sabnzbd/skintext.py [#: Config->Scheduler] msgid "Read RSS feeds" msgstr "读取 RSS feed" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove failed jobs" msgstr "移除失败任务" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Remove completed jobs" msgstr "移除已完成任务" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause low prioirty jobs" msgstr "暂停低优先级任务" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause normal prioirty jobs" msgstr "暂停常规优先级任务" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause high prioirty jobs" msgstr "暂停高优先级任务" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume low prioirty jobs" msgstr "继续低优先级任务" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume normal prioirty jobs" msgstr "继续常规优先级任务" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume high prioirty jobs" msgstr "继续高优先级任务" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Enable quota management" msgstr "启用配额管理" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Disable quota management" msgstr "禁用配额管理" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Pause jobs with category" msgstr "" #: sabnzbd/skintext.py [Config->Scheduler] msgid "Resume jobs with category" msgstr "" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Three way switch for duplicates] msgid "Off" msgstr "关" #: sabnzbd/skintext.py [Prowl priority] msgid "Very Low" msgstr "非常低" #: sabnzbd/skintext.py [Prowl priority] msgid "Moderate" msgstr "适中" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Normal" msgstr "常规" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "High" msgstr "高" #: sabnzbd/skintext.py [Prowl priority] msgid "Emergency" msgstr "紧急" #: sabnzbd/skintext.py [Prowl priority] # sabnzbd/skintext.py [Priority pick list] msgid "Low" msgstr "低" #: sabnzbd/skintext.py [Megabytes] msgid "MB" msgstr "MB" #: sabnzbd/skintext.py [Gigabytes] msgid "GB" msgstr "GB" #: sabnzbd/skintext.py [One hour] msgid "hour" msgstr "小时" #: sabnzbd/skintext.py [Multiple hours] msgid "hours" msgstr "小时" #: sabnzbd/skintext.py [One minute] msgid "min" msgstr "分钟" #: sabnzbd/skintext.py [Multiple minutes] msgid "mins" msgstr "分钟" #: sabnzbd/skintext.py [One second] msgid "sec" msgstr "秒" #: sabnzbd/skintext.py [Multiple seconds] msgid "seconds" msgstr "秒" #: sabnzbd/skintext.py msgid "day" msgstr "天" #: sabnzbd/skintext.py msgid "days" msgstr "天" #: sabnzbd/skintext.py msgid "week" msgstr "周" #: sabnzbd/skintext.py msgid "Month" msgstr "月" #: sabnzbd/skintext.py msgid "Year" msgstr "年" #: sabnzbd/skintext.py msgid "January" msgstr "" #: sabnzbd/skintext.py msgid "February" msgstr "" #: sabnzbd/skintext.py msgid "March" msgstr "" #: sabnzbd/skintext.py msgid "April" msgstr "" #: sabnzbd/skintext.py msgid "May" msgstr "" #: sabnzbd/skintext.py msgid "June" msgstr "" #: sabnzbd/skintext.py msgid "July" msgstr "" #: sabnzbd/skintext.py msgid "August" msgstr "" #: sabnzbd/skintext.py msgid "September" msgstr "" #: sabnzbd/skintext.py msgid "October" msgstr "" #: sabnzbd/skintext.py msgid "November" msgstr "" #: sabnzbd/skintext.py msgid "December" msgstr "" #: sabnzbd/skintext.py msgid "Day of month" msgstr "每月特定一天" #: sabnzbd/skintext.py msgid "This week" msgstr "本周" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "This month" msgstr "本月" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Today" msgstr "今天" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Total" msgstr "总计" #: sabnzbd/skintext.py msgid "on" msgstr "开" #: sabnzbd/skintext.py [Config: startup parameters of SABnzbd] # sabnzbd/skintext.py [Notification Script settings] msgid "Parameters" msgstr "参数" #: sabnzbd/skintext.py msgid "Python Version" msgstr "Python 版本" #: sabnzbd/skintext.py [Home page of the SABnzbd project] msgid "Home page" msgstr "主页" #: sabnzbd/skintext.py [Used in "IRC or IRC-Webaccess"] msgid "or" msgstr "或" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server hostname or IP] msgid "Host" msgstr "主机" #: sabnzbd/skintext.py msgid "Comment" msgstr "评论" #: sabnzbd/skintext.py msgid "Send" msgstr "发送" #: sabnzbd/skintext.py msgid "Cancel" msgstr "取消" #: sabnzbd/skintext.py msgid "Other" msgstr "其他" #: sabnzbd/skintext.py msgid "Report" msgstr "报告" #: sabnzbd/skintext.py msgid "Video" msgstr "视频" #: sabnzbd/skintext.py msgid "Audio" msgstr "音频" #: sabnzbd/skintext.py msgid "Not used" msgstr "未使用" #: sabnzbd/skintext.py msgid "or less" msgstr "或更少" #: sabnzbd/skintext.py msgid "Log in" msgstr "登录" #: sabnzbd/skintext.py msgid "Log out" msgstr "注销" #: sabnzbd/skintext.py msgid "Remember me" msgstr "记住我" #: sabnzbd/skintext.py [SABnzbd's theme line] msgid "The automatic usenet download tool" msgstr "usenet 自动下载工具" #: sabnzbd/skintext.py ["Save" button] msgid "Save" msgstr "保存" #: sabnzbd/skintext.py [Used in confirmation popups] # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Are you sure?" msgstr "是否确定?" #: sabnzbd/skintext.py [Used in confirmation popups] msgid "Delete all downloaded files?" msgstr "删除全部已下载文件?" #: sabnzbd/skintext.py [Main menu item] msgid "Home" msgstr "主页" #: sabnzbd/skintext.py [Main menu item] msgid "Config" msgstr "配置" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py [History table header] msgid "Status" msgstr "状态" #: sabnzbd/skintext.py [Main menu item] msgid "Help" msgstr "帮助" #: sabnzbd/skintext.py [Main menu item] msgid "Forum" msgstr "论坛" #: sabnzbd/skintext.py [Main menu item] msgid "IRC" msgstr "IRC" #: sabnzbd/skintext.py [Main menu item] msgid "Issues" msgstr "问题" #: sabnzbd/skintext.py [Main menu item] msgid "Support the project, Donate!" msgstr "支持该项目,捐助!" #: sabnzbd/skintext.py [Main menu item] msgid "General" msgstr "常规" #: sabnzbd/skintext.py [Main menu item] msgid "Folders" msgstr "文件夹" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Switches" msgstr "参数" #: sabnzbd/skintext.py [Main menu item] msgid "Scheduling" msgstr "定时任务" #: sabnzbd/skintext.py [Main menu item] msgid "RSS" msgstr "RSS" #: sabnzbd/skintext.py [Main menu item] msgid "Notifications" msgstr "通知" #: sabnzbd/skintext.py [Main menu item] msgid "Email" msgstr "Email" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Categories" msgstr "分类" #: sabnzbd/skintext.py [Main menu item] msgid "Sorting" msgstr "排序" #: sabnzbd/skintext.py [Main menu item] msgid "Special" msgstr "特殊" #: sabnzbd/skintext.py [Main menu item] # sabnzbd/skintext.py msgid "Search" msgstr "搜索" #: sabnzbd/skintext.py msgid "Download Dir" msgstr "下载目录" #: sabnzbd/skintext.py msgid "PAUSED" msgstr "*已暂停*" #: sabnzbd/skintext.py msgid "Cached %s articles (%s)" msgstr "已缓存 %s 篇文章 (%s)" #: sabnzbd/skintext.py msgid "Sysload" msgstr "系统负载" #: sabnzbd/skintext.py msgid "New release %s available at" msgstr "新版 %s 已发布,下载:" #: sabnzbd/skintext.py msgid "Are you sure you want to shutdown SABnzbd?" msgstr "是否确定要关闭 SABnzbd?" #: sabnzbd/skintext.py [Add NZB to queue (button)] # sabnzbd/skintext.py [Add NZB to queue (header)] msgid "Add" msgstr "添加" #: sabnzbd/skintext.py [Add NZB file to queue (header] msgid "Add File" msgstr "添加文件" #: sabnzbd/skintext.py [Job category] msgid "Category" msgstr "分类" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Queue page table column header] msgid "Processing" msgstr "处理" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Server priority] msgid "Priority" msgstr "优先级" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Repair" msgstr "+修复" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Unpack" msgstr "+解压" #: sabnzbd/skintext.py [Post processing pick list] msgid "+Delete" msgstr "+删除" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Repair"] msgid "R" msgstr "修" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Unpack"] msgid "U" msgstr "解" #: sabnzbd/skintext.py [Post processing pick list: abbreviation for "+Delete"] msgid "D" msgstr "删" #: sabnzbd/skintext.py [Priority pick list] msgid "Force" msgstr "强制" #: sabnzbd/skintext.py [Priority pick list] msgid "Stop" msgstr "停止" #: sabnzbd/skintext.py [Add NZB Dialog] msgid "Enter URL" msgstr "输入 URL" #: sabnzbd/skintext.py [Queue page selection menu] # sabnzbd/skintext.py msgid "On queue finish" msgstr "队列完成时" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown PC" msgstr "电脑关闭" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Standby PC" msgstr "电脑待机" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Hibernate PC" msgstr "电脑休眠" #: sabnzbd/skintext.py [Queue page end-of-queue action] msgid "Shutdown SABnzbd" msgstr "关闭 SABnzbd" #: sabnzbd/skintext.py [Queue page selection menu or entry box] msgid "Speed Limit" msgstr "限速" #: sabnzbd/skintext.py [Queue page button or entry box] msgid "Pause for" msgstr "暂停" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Order" msgstr "序号" #: sabnzbd/skintext.py [Queue page table column header] # sabnzbd/skintext.py [Job details page] msgid "Name" msgstr "名称" #: sabnzbd/skintext.py [Queue page table column header, "estimated time of arrival"] msgid "ETA" msgstr "大约完成" #: sabnzbd/skintext.py [Queue page table column header, "age of the NZB"] msgid "AGE" msgstr "发布时间" #: sabnzbd/skintext.py [Queue page table, "Delete" button] msgid "Del" msgstr "删除" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Retry" msgstr "重试" #: sabnzbd/skintext.py [Queue end-of-queue selection box] msgid "Actions" msgstr "操作" #: sabnzbd/skintext.py [Queue page table, script selection menu] msgid "Scripts" msgstr "脚本" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all items from the queue?" msgstr "删除队列中全部项?" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs" msgstr "清空 NZB" #: sabnzbd/skintext.py [Queue page button] msgid "Purge NZBs & Delete Files" msgstr "清空 NZB 并删除文件" #: sabnzbd/skintext.py [Retry all failed jobs dialog box] msgid "Retry all failed jobs" msgstr "重新尝试下载所有已失败任务" #: sabnzbd/skintext.py [Queue page button] msgid "Remove NZB" msgstr "移除 NZB" #: sabnzbd/skintext.py [Queue page button] # sabnzbd/skintext.py msgid "Remove NZB & Delete Files" msgstr "移除 NZB 并删除文件" #: sabnzbd/skintext.py [Queue page, as in "4G *of* 10G"] msgid "of" msgstr "/" #: sabnzbd/skintext.py [Caption for missing articles in Queue] msgid "Missing articles" msgstr "缺失文章" #: sabnzbd/skintext.py [Remaining quota (displayed in Queue)] msgid "Quota left" msgstr "剩余配额" #: sabnzbd/skintext.py [Manual reset of quota] msgid "manual" msgstr "手动" #: sabnzbd/skintext.py msgid "Reset Quota now" msgstr "立即重置配额" #: sabnzbd/skintext.py [Confirmation popup] msgid "Delete all completed items from History?" msgstr "从“历史”中删除所有已完成项?" #: sabnzbd/skintext.py [Button/link hiding History job details] msgid "Hide details" msgstr "隐藏详情" #: sabnzbd/skintext.py [Button/link showing History job details] msgid "Show details" msgstr "显示详情" #: sabnzbd/skintext.py [Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG!] msgid "Show Failed" msgstr "只显示失败项" #: sabnzbd/skintext.py [Button or link showing all History jobs] msgid "Show All" msgstr "显示全部项" #: sabnzbd/skintext.py [History table header] # sabnzbd/skintext.py [Size of the download quota] # sabnzbd/skintext.py msgid "Size" msgstr "尺寸" #: sabnzbd/skintext.py [Button to delete all failed jobs in History] msgid "Purge Failed NZBs" msgstr "清除失败 NZB" #: sabnzbd/skintext.py [Button to delete all failed jobs in History, including files] msgid "Purge Failed NZBs & Delete Files" msgstr "清除失败 NZB 并删除文件" #: sabnzbd/skintext.py [Button to delete all completed jobs in History] msgid "Purge Completed NZBs" msgstr "清除已完成 NZB" #: sabnzbd/skintext.py [Button to delete jobs on current page in History] msgid "Purge NZBs on the current page" msgstr "清理本页的 NZB 文件" #: sabnzbd/skintext.py [Button to add NZB to failed job in History] msgid "Optional Supplemental NZB" msgstr "可选补充 NZB" #: sabnzbd/skintext.py [Path as displayed in History details] # sabnzbd/skintext.py msgid "Path" msgstr "路径" #: sabnzbd/skintext.py [Retry all failed jobs in History] msgid "Retry all failed" msgstr "重试所有失败任务" #: sabnzbd/skintext.py [Retry all button for Retry All Failed Jobs] msgid "Retry All" msgstr "重试所有" #: sabnzbd/skintext.py msgid "Virus/spam" msgstr "病毒/垃圾" #: sabnzbd/skintext.py msgid "Out of retention" msgstr "超出保留期" #: sabnzbd/skintext.py msgid "Other problem" msgstr "其他问题" #: sabnzbd/skintext.py [Status page button] msgid "Force Disconnect" msgstr "强制断开连接" #: sabnzbd/skintext.py msgid "This will send a test email to your account." msgstr "这将发送一封测试邮件到您的账号当中。" #: sabnzbd/skintext.py [Status page button] msgid "Show Logging" msgstr "显示日志" #: sabnzbd/skintext.py [Status page button] msgid "Test Email" msgstr "测试邮件" #: sabnzbd/skintext.py [Status page selection menu] msgid "Logging" msgstr "日志" #: sabnzbd/skintext.py [Status page table header] msgid "Errors/Warning" msgstr "错误/警告" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Info" msgstr "+ 信息" #: sabnzbd/skintext.py [Status page logging selection value] msgid "+ Debug" msgstr "+ 调试" #: sabnzbd/skintext.py [Status page tab header] # sabnzbd/skintext.py [Server: amount of connections] msgid "Connections" msgstr "连接" #: sabnzbd/skintext.py [Status page, table header] msgid "Latest Warnings" msgstr "最新警告信息" #: sabnzbd/skintext.py [Status page button] msgid "clear" msgstr "清除" #: sabnzbd/skintext.py [Status page button] # sabnzbd/skintext.py msgid "Unblock" msgstr "解封" #: sabnzbd/skintext.py [Status page, article identifier] msgid "Article identifier" msgstr "文章 id" #: sabnzbd/skintext.py [Status page, par-set that article belongs to] msgid "File set" msgstr "文件集" #: sabnzbd/skintext.py [Status page, table column header, when error occured] msgid "When" msgstr "时间" #: sabnzbd/skintext.py [Status page, table column header, type of message] # sabnzbd/skintext.py [Config->RSS table column header] msgid "Type" msgstr "类型" #: sabnzbd/skintext.py [Status page, indicator that server is enabled] msgid "Enabled" msgstr "启用" #: sabnzbd/skintext.py msgid "Dashboard" msgstr "控制台" #: sabnzbd/skintext.py msgid "Connection failed!" msgstr "连接失败!" #: sabnzbd/skintext.py msgid "Local IPv4 address" msgstr "本地 IPv4 地址" #: sabnzbd/skintext.py msgid "Public IPv4 address" msgstr "公网 IPv4 地址" #: sabnzbd/skintext.py msgid "IPv6 address" msgstr "IPv6 地址" #: sabnzbd/skintext.py msgid "Nameserver / DNS Lookup" msgstr "域名服务器 / DNS 查询" #: sabnzbd/skintext.py msgid "CPU Model" msgstr "CPU 型号" #: sabnzbd/skintext.py [Do not translate Pystone] msgid "System Performance (Pystone)" msgstr "系统性能 (Pystone)" #: sabnzbd/skintext.py msgid "Download folder speed" msgstr "下载文件夹读写速度" #: sabnzbd/skintext.py msgid "Complete folder speed" msgstr "完成文件夹写入速度" #: sabnzbd/skintext.py msgid "Writing speed" msgstr "写入速度" #: sabnzbd/skintext.py msgid "Could not write. Check that the directory is writable." msgstr "无法写入。请确保该目录有写入权限。" #: sabnzbd/skintext.py msgid "Click on Repeat test button below to determine" msgstr "点击下面的“重复”按钮可开始测试" #: sabnzbd/skintext.py msgid "Repeat test" msgstr "重复测试" #: sabnzbd/skintext.py msgid "Config File" msgstr "配置文件" #: sabnzbd/skintext.py [Main config page, how much cache is in use] msgid "Used cache" msgstr "已用缓存" #: sabnzbd/skintext.py msgid "" "This will restart SABnzbd.
Use it when you think the program has a " "stability problem.
Downloading will be paused before the restart and " "resume afterwards." msgstr "这将重新启动 SABnzbd。
如果您认为程序存在稳定性问题,请使用该项。
重启前将暂停下载,之后将继续下载。" #: sabnzbd/skintext.py msgid "
If authentication is enabled, you will need to login again." msgstr "
若启用身份认证,您将需要重新登录。" #: sabnzbd/skintext.py msgid "Advanced" msgstr "高级" #: sabnzbd/skintext.py msgid "" "There are orphaned jobs in the download folder.
You can choose to " "delete them (including files) or send them back to the queue." msgstr "下载目录中存在孤立任务。
您可以选择删除任务 (及其文件) 或将它们发回队列。" #: sabnzbd/skintext.py msgid "" "The \"Repair\" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded " "files.
This will modify the queue order." msgstr "“修复”按钮可重启 SABnzbd 并执行完整的
队列内容重建操作,同时将保留已下载的文件。
队列的顺序会有所改变。" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Changes have not been saved, and will be lost." msgstr "更改未保存,改动将丢失。" #: sabnzbd/skintext.py msgid "" "When your IP address changes or SABnzbd is restarted the session will expire." msgstr "每当您的 IP 地址发生变化,或当 SABnzbd 重启,登录会话将自动过期。" #: sabnzbd/skintext.py msgid "Enable Unzip" msgstr "启用 Unzip" #: sabnzbd/skintext.py msgid "Enable 7zip" msgstr "启用 7zip" #: sabnzbd/skintext.py msgid "Multicore Par2" msgstr "" #: sabnzbd/skintext.py msgid "" "Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will " "be encrypted, however, validating a server's identity using its certificates " "is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-" "date local CA certificates are required." msgstr "" "SABnzbd 与新闻组服务器之间的安全连接 (SSL) 以及 HTTPS 网站将会被加密,只不过,使用证书来验证服务器的身份却无法实现。要求 " "Python 2.7.9 或以上,OpenSSL 1.0.2 或以上,以及最新的本地 CA 证书存储。" #: sabnzbd/skintext.py msgid "" "Speed up repairs by installing multicore Par2, it is available for many " "platforms." msgstr "安装支持多核心的 Par2 以便加快修复速度,支持多平台。" #: sabnzbd/skintext.py msgid "Version" msgstr "版本" #: sabnzbd/skintext.py msgid "Uptime" msgstr "启动时间" #: sabnzbd/skintext.py [Indicates that server is Backup server in Status page] msgid "Backup" msgstr "备份" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py #: sabnzbd/skintext.py # sabnzbd/skintext.py [Notification Script settings] msgid "Read the Wiki Help on this!" msgstr "关于该项请参阅 Wiki 帮助!" #: sabnzbd/skintext.py msgid "Restarting SABnzbd..." msgstr "正在重新启动 SABnzbd..." #: sabnzbd/skintext.py msgid "Changes will require a SABnzbd restart!" msgstr "变更需要重启 SABnzbd 才会生效!" #: sabnzbd/skintext.py msgid "SABnzbd Web Server" msgstr "SABnzbd Web 服务器" #: sabnzbd/skintext.py msgid "SABnzbd Host" msgstr "SABnzbd 主机" #: sabnzbd/skintext.py msgid "Host SABnzbd should listen on." msgstr "SABnzbd 应监听的主机。" #: sabnzbd/skintext.py msgid "SABnzbd Port" msgstr "SABnzbd 端口" #: sabnzbd/skintext.py msgid "Port SABnzbd should listen on." msgstr "SABnzbd 应监听的端口。" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Web Interface" msgstr "Web 界面" #: sabnzbd/skintext.py msgid "Choose a skin." msgstr "选择皮肤。" #: sabnzbd/skintext.py msgid "SABnzbd Username" msgstr "SABnzbd 用户名" #: sabnzbd/skintext.py msgid "Optional authentication username." msgstr "可选身份验证用户名。" #: sabnzbd/skintext.py msgid "SABnzbd Password" msgstr "SABnzbd 密码" #: sabnzbd/skintext.py msgid "Optional authentication password." msgstr "可选身份验证密码。" #: sabnzbd/skintext.py msgid "" "If the SABnzbd Host or Port is exposed to the internet, your current " "settings allow full external access to the SABnzbd interface." msgstr "" #: sabnzbd/skintext.py msgid "Security" msgstr "安全" #: sabnzbd/skintext.py msgid "Enable HTTPS" msgstr "启用 HTTPS" #: sabnzbd/skintext.py msgid "not installed" msgstr "未安装" #: sabnzbd/skintext.py msgid "Enable accessing the interface from a HTTPS address." msgstr "启用 HTTPS 地址访问界面。" #: sabnzbd/skintext.py msgid "HTTPS Port" msgstr "HTTPS 端口" #: sabnzbd/skintext.py msgid "If empty, the standard port will only listen to HTTPS." msgstr "若留空,则将监听 HTTPS 标准端口。" #: sabnzbd/skintext.py msgid "HTTPS Certificate" msgstr "HTTPS 证书" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Certificate." msgstr "HTTPS 证书文件名或路径。" #: sabnzbd/skintext.py msgid "" "Generate new self-signed certificate and key. Requires SABnzbd restart!" msgstr "生成新的自签名证书和密钥。需要重启 SABnzbd!" #: sabnzbd/skintext.py msgid "HTTPS Key" msgstr "HTTPS Key" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Key." msgstr "HTTPS Key 文件名或路径。" #: sabnzbd/skintext.py msgid "HTTPS Chain Certifcates" msgstr "HTTPS 链证书" #: sabnzbd/skintext.py msgid "File name or path to HTTPS Chain." msgstr "HTTPS 链文件名或路径。" #: sabnzbd/skintext.py msgid "Tuning" msgstr "调节" #: sabnzbd/skintext.py msgid "RSS Checking Interval" msgstr "RSS 检查间隔" #: sabnzbd/skintext.py msgid "" "Checking interval (in minutes, at least 15). Not active when you use the " "Scheduler!" msgstr "检查间隔 (分钟,最小值为 15)。若使用“定时任务”则不会有效!" #: sabnzbd/skintext.py msgid "Maximum line speed" msgstr "最大线路速度" #: sabnzbd/skintext.py msgid "Percentage of line speed" msgstr "线路速度的百分比" #: sabnzbd/skintext.py msgid "Which percentage of the linespeed should SABnzbd use, e.g. 50" msgstr "SABnzbd 应占用的线路速度的百分比,如 50" #: sabnzbd/skintext.py msgid "Article Cache Limit" msgstr "文章缓存限制" #: sabnzbd/skintext.py msgid "" "Cache articles in memory to reduce disk access.
In bytes, optionally " "follow with K,M,G. For example: \"64M\" or \"128M\"" msgstr "" "在内存中缓存文章,以减轻硬盘访问压力。
单位为字节,可以选择加上 K、M、G 后缀。例如: \"64M\" 或 \"128M\"" #: sabnzbd/skintext.py msgid "Cleanup List" msgstr "清理列表" #: sabnzbd/skintext.py msgid "" "List of file extensions that should be deleted after download.
For " "example: nfo or nfo, sfv" msgstr "下载后应删除的文件扩展名列表。
例如: nfo 或 nfo, sfv" #: sabnzbd/skintext.py msgid "History Retention" msgstr "" #: sabnzbd/skintext.py msgid "" "Automatically delete completed jobs from History. Beware that Duplicate " "Detection and some external tools rely on History information." msgstr "" #: sabnzbd/skintext.py msgid "Keep all jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep maximum number of completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Keep completed jobs maximum number of days" msgstr "" #: sabnzbd/skintext.py msgid "Do not keep any completed jobs" msgstr "" #: sabnzbd/skintext.py msgid "Jobs" msgstr "" #: sabnzbd/skintext.py msgid "Save Changes" msgstr "保存更改" #: sabnzbd/skintext.py msgid "Restore Defaults" msgstr "恢复默认值" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Reset" msgstr "重置" #: sabnzbd/skintext.py msgid "Language" msgstr "语言" #: sabnzbd/skintext.py msgid "Select a web interface language." msgstr "选择 web 界面的语言。" #: sabnzbd/skintext.py msgid "" "Help us translate SABnzbd in your language!
Add untranslated texts or " "improved existing translations here:" msgstr "帮助我们来本地化 SABnzbd !
您可以在这里来添加未被翻译的文字或者改进现有的翻译:" #: sabnzbd/skintext.py msgid "This key will give 3rd party programs full access to SABnzbd." msgstr "该 key 将授予第三方程序 SABnzbd 的完整权限。" #: sabnzbd/skintext.py msgid "NZB Key" msgstr "NZB Key" #: sabnzbd/skintext.py msgid "This key will allow 3rd party programs to add NZBs to SABnzbd." msgstr "该 key 将允许第三方程序将 NZB 添加到 SABnzbd 中。" #: sabnzbd/skintext.py msgid "Generate New Key" msgstr "生成新的 Key" #: sabnzbd/skintext.py [Explanation for QR code of APIKEY] msgid "API Key QR Code" msgstr "API Key QR 码" #: sabnzbd/skintext.py msgid "List of local network ranges" msgstr "本地网段列表" #: sabnzbd/skintext.py msgid "" "All local network addresses start with these prefixes (often \"192.168.1.\")" msgstr "本地网络地址以这些前缀开头 (通常为“192.168.1.”)" #: sabnzbd/skintext.py msgid "External internet access" msgstr "外部互联网访问" #: sabnzbd/skintext.py msgid "" "You can set access rights for systems outside your local network. Requires " "List of local network ranges to be defined." msgstr "您可以设定非本地网络的访问权限。要求定义本地网络列表。" #: sabnzbd/skintext.py msgid "No access" msgstr "无权访问" #: sabnzbd/skintext.py msgid "Add NZB files " msgstr "添加 NZB 文件 " #: sabnzbd/skintext.py msgid "API (no Config)" msgstr "API (不允许配置)" #: sabnzbd/skintext.py msgid "Full API" msgstr "完整 API" #: sabnzbd/skintext.py msgid "Full Web interface" msgstr "完整 Web 界面" #: sabnzbd/skintext.py msgid "Only external access requires login" msgstr "只对外部访问要求登录" #: sabnzbd/skintext.py msgid "" "NOTE: Folders will be created automatically when Saving. You may " "use absolute paths to save outside of the default folders." msgstr "注: 保存时将自动创建文件夹。您可以使用绝对路径以保存到默认文件夹以外的地方。" #: sabnzbd/skintext.py msgid "User Folders" msgstr "用户文件夹" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Browse" msgstr "浏览" #: sabnzbd/skintext.py msgid "In" msgstr "位于" #: sabnzbd/skintext.py msgid "Temporary Download Folder" msgstr "临时下载文件夹" #: sabnzbd/skintext.py msgid "" "Location to store unprocessed downloads.
Can only be changed when " "queue is empty." msgstr "存储未处理下载数据的位置。
仅当队列为空时可以更改。" #: sabnzbd/skintext.py msgid "Minimum Free Space for Temporary Download Folder" msgstr "临时下载文件夹的最小剩余空间" #: sabnzbd/skintext.py msgid "" "Auto-pause when free space is beneath this value.
In bytes, " "optionally follow with K,M,G,T. For example: \"800M\" or \"8G\"" msgstr "" "当剩余空间低于该值时自动暂停。
单位为字节,可选添加 K、M、G、T 后缀。例如: \"800M\" 或 \"8G\"" #: sabnzbd/skintext.py msgid "Completed Download Folder" msgstr "完成下载文件夹" #: sabnzbd/skintext.py msgid "" "Location to store finished, fully processed downloads.
Can be " "overruled by user-defined categories." msgstr "存储完成且已完全处理的下载数据的位置。
可以通过用户定义分类额外调整。" #: sabnzbd/skintext.py msgid "Permissions for completed downloads" msgstr "完成下载权限" #: sabnzbd/skintext.py msgid "" "Set permissions pattern for completed files/folders.
In octal " "notation. For example: \"755\" or \"777\"" msgstr "设置完成文件/文件夹的权限值。
八进制记法。例如: \"755\" 或 \"777\"" #: sabnzbd/skintext.py msgid "Watched Folder" msgstr "监视文件夹" #: sabnzbd/skintext.py msgid "" "Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz " "archives for .nzb files." msgstr "" "要监视 .nzb 文件的文件夹。
会同时扫描 .zip .rar 及 .tar.gz 压缩文件中的 .nzb 文件。" #: sabnzbd/skintext.py msgid "Watched Folder Scan Speed" msgstr "监视文件夹扫描速度" #: sabnzbd/skintext.py msgid "Number of seconds between scans for .nzb files." msgstr "扫描 .nzb 文件的间隔时间。" #: sabnzbd/skintext.py msgid "Scripts Folder" msgstr "脚本文件夹" #: sabnzbd/skintext.py msgid "Folder containing user scripts." msgstr "包含用户脚本的文件夹。" #: sabnzbd/skintext.py msgid "Email Templates Folder" msgstr "邮件模板文件夹" #: sabnzbd/skintext.py msgid "Folder containing user-defined email templates." msgstr "包含用户定义的电子邮件模板的文件夹。" #: sabnzbd/skintext.py msgid "Password file" msgstr "密码文件" #: sabnzbd/skintext.py msgid "File containing all passwords to be tried on encrypted RAR files." msgstr "包含要对加密 RAR 文件进行尝试的所有密码的文件。" #: sabnzbd/skintext.py msgid "System Folders" msgstr "系统文件夹" #: sabnzbd/skintext.py msgid "Administrative Folder" msgstr "管理文件夹" #: sabnzbd/skintext.py msgid "" "Location for queue admin and history database.
Can only be changed " "when queue is empty." msgstr "队列管理及历史数据库的存放位置。
仅当队列为空时可以修改。" #: sabnzbd/skintext.py msgid "Data will not be moved. Requires SABnzbd restart!" msgstr "数据不会自动移动。需要重启 SABnzbd 才能生效!" #: sabnzbd/skintext.py msgid "Log Folder" msgstr "日志文件夹" #: sabnzbd/skintext.py msgid "" "Location of log files for SABnzbd.
Requires SABnzbd restart!" msgstr "SABnzbd 日志文件的位置。
需要重启 SABnzbd 才能生效!" #: sabnzbd/skintext.py msgid ".nzb Backup Folder" msgstr ".nzb 备份文件夹" #: sabnzbd/skintext.py msgid "Location where .nzb files will be stored." msgstr "存储 .nzb 文件的位置。" #: sabnzbd/skintext.py msgid "Default Base Folder" msgstr "默认基本文件夹" #: sabnzbd/skintext.py msgid "Download all par2 files" msgstr "下载所有 par2 文件" #: sabnzbd/skintext.py msgid "" "This prevents multiple repair runs by downloading all par2 files when needed." msgstr "当需要时下载所有的 par2 文件以避免多次运行修复。" #: sabnzbd/skintext.py msgid "Enable recursive unpacking" msgstr "启用递归解压" #: sabnzbd/skintext.py msgid "Unpack archives (rar, zip, 7z) within archives." msgstr "解压压缩包内的压缩包 (rar, zip, 7z)。" #: sabnzbd/skintext.py msgid "Ignore any folders inside archives" msgstr "忽略压缩包中的文件夹结构" #: sabnzbd/skintext.py msgid "All files will go into a single folder." msgstr "所有文件保存到单个目录。" #: sabnzbd/skintext.py msgid "Only Get Articles for Top of Queue" msgstr "只获取队列最顶端的文章" #: sabnzbd/skintext.py msgid "" "Enable for less memory usage. Disable to prevent slow jobs from blocking the " "queue." msgstr "启用可减少内存占用。禁用可避免慢速任务拖慢队列进度。" #: sabnzbd/skintext.py msgid "Post-Process Only Verified Jobs" msgstr "仅对经验证的任务进行后期处理" #: sabnzbd/skintext.py msgid "Only perform post-processing on jobs that passed all PAR2 checks." msgstr "仅对通过全部 PAR2 检查的任务执行后期处理。" #: sabnzbd/skintext.py msgid "Action when encrypted RAR is downloaded" msgstr "下载到加密的 RAR 文件时采取的操作" #: sabnzbd/skintext.py msgid "" "In case of \"Pause\", you'll need to set a password and resume the job." msgstr "若选择“暂停”,您将需要设置密码并手动续传对应任务。" #: sabnzbd/skintext.py msgid "Detect Duplicate Downloads" msgstr "侦测重复下载" #: sabnzbd/skintext.py msgid "" "Detect identical NZB files (based on items in your History or files in .nzb " "Backup Folder)" msgstr "检测相同的 NZB 文件 (基于您的历史项目或 .nzb 备份文件夹中的文件)" #: sabnzbd/skintext.py msgid "Detect duplicate episodes in series" msgstr "侦测同季的重复剧集" #: sabnzbd/skintext.py msgid "" "Detect identical episodes in series (based on \"name/season/episode\" of " "items in your History)" msgstr "在剧目中检测相同的剧集 (基于您的历史项目,参照 \"name/season/episode\" 的规则)" #: sabnzbd/skintext.py msgid "Allow proper releases" msgstr "" #: sabnzbd/skintext.py msgid "" "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in " "the download name" msgstr "" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Discard" msgstr "舍弃" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Fail job (move to History)" msgstr "失败的任务 (移动到历史)" #: sabnzbd/skintext.py [Four way switch for duplicates] msgid "Tag job" msgstr "" #: sabnzbd/skintext.py [Three way switch for encrypted posts] msgid "Abort" msgstr "中止" #: sabnzbd/skintext.py msgid "Action when unwanted extension detected" msgstr "侦测到不需要的扩展名时的操作" #: sabnzbd/skintext.py msgid "Action when an unwanted extension is detected in RAR files" msgstr "RAR 文件中侦测到不需要的扩展名时的操作" #: sabnzbd/skintext.py msgid "Unwanted extensions" msgstr "不需要的扩展名" #: sabnzbd/skintext.py msgid "" "List all unwanted extensions. For example: exe or exe, com" msgstr "所有不需要扩展名的列表。例如: exe 或 exe, com" #: sabnzbd/skintext.py msgid "Enable SFV-based checks" msgstr "启用基于 SFV 的检查" #: sabnzbd/skintext.py msgid "Do an extra verification based on SFV files." msgstr "根据 SFV 文件进行额外验证。" #: sabnzbd/skintext.py msgid "User script can flag job as failed" msgstr "用户脚本可将任务标记为失败" #: sabnzbd/skintext.py msgid "" "When the user script returns a non-zero exit code, the job will be flagged " "as failed." msgstr "用户脚本返回非零的退出代码时,对应的任务将被标记为失败。" #: sabnzbd/skintext.py msgid "On failure, try alternative NZB" msgstr "失败时,尝试备用 NZB" #: sabnzbd/skintext.py msgid "Some servers provide an alternative NZB when a download fails." msgstr "部分服务器在下载失败时可提供备用 NZB 文件。" #: sabnzbd/skintext.py msgid "Use tags from indexer" msgstr "" #: sabnzbd/skintext.py msgid "" "When sorting, use tags from indexer for title, season, episode, etc. " "Otherwise all naming is derived from the NZB name." msgstr "" #: sabnzbd/skintext.py msgid "Enable folder rename" msgstr "启用文件夹重命名" #: sabnzbd/skintext.py msgid "" "Use temporary names during post processing. Disable when your system doesn't " "handle that properly." msgstr "后期处理过程中使用临时名称。若您的系统无法正常处理请禁用。" #: sabnzbd/skintext.py msgid "Pre-queue user script" msgstr "加入队列前执行的用户脚本" #: sabnzbd/skintext.py msgid "Used before an NZB enters the queue." msgstr "用于在 NZB 进入队列前执行。" #: sabnzbd/skintext.py msgid "Extra PAR2 Parameters" msgstr "额外的 PAR2 参数" #: sabnzbd/skintext.py msgid "Nice Parameters" msgstr "Nice 参数" #: sabnzbd/skintext.py msgid "IONice Parameters" msgstr "IONice 参数" #: sabnzbd/skintext.py msgid "Disconnect on Empty Queue" msgstr "清空队列时断开" #: sabnzbd/skintext.py msgid "Disconnect from Usenet server(s) when queue is empty or paused." msgstr "队列为空或暂停时从 Usenet 服务器断开连接。" #: sabnzbd/skintext.py msgid "Sort by Age" msgstr "按发布时间排列" #: sabnzbd/skintext.py msgid "Automatically sort items by (average) age." msgstr "自动按 (平均) 发布时间排列项目。" #: sabnzbd/skintext.py msgid "" "Posts will be paused untill they are at least this age. Setting job priority " "to Force will skip the delay." msgstr "在文章发布时长尚不足该值时暂停下载文章。将任务优先级设为“强制”可跳过此延迟。" #: sabnzbd/skintext.py msgid "Check for New Release" msgstr "检查新版本" #: sabnzbd/skintext.py msgid "Weekly check for new SABnzbd release." msgstr "每周检查 SABnzbd 的新版本。" #: sabnzbd/skintext.py [Pick list for weekly test for new releases] msgid "Also test releases" msgstr "同时检索测试版本信息" #: sabnzbd/skintext.py msgid "Replace Spaces in Foldername" msgstr "替换文件夹名称中的空格" #: sabnzbd/skintext.py msgid "Replace spaces with underscores in folder names." msgstr "将文件夹名称中的空格替换成下划线。" #: sabnzbd/skintext.py msgid "Replace dots in Foldername" msgstr "替换文件夹名称中的点号" #: sabnzbd/skintext.py msgid "Replace dots with spaces in folder names." msgstr "将文件夹名称中的小数点替换成空格。" #: sabnzbd/skintext.py msgid "Make Windows compatible" msgstr "确保与 Windows 兼容" #: sabnzbd/skintext.py msgid "For servers: make sure names are compatible with Windows." msgstr "供服务器使用: 确保名称与 Windows 系统兼容。" #: sabnzbd/skintext.py msgid "Launch Browser on Startup" msgstr "启动时启动浏览器" #: sabnzbd/skintext.py msgid "Launch the default web browser when starting SABnzbd." msgstr "启动 SABnzbd 时启动默认 web 浏览器。" #: sabnzbd/skintext.py msgid "Pause Downloading During Post-Processing" msgstr "后期处理过程中暂停下载" #: sabnzbd/skintext.py msgid "" "Pauses downloading at the start of post processing and resumes when finished." msgstr "开始后期处理时暂停下载,完成后续传。" #: sabnzbd/skintext.py msgid "Ignore Samples" msgstr "忽略样本文件" #: sabnzbd/skintext.py msgid "Filter out sample files (e.g. video samples)." msgstr "过滤样本文件 (如视频样本)。" #: sabnzbd/skintext.py msgid "Delete after download" msgstr "下载后删除" #: sabnzbd/skintext.py msgid "HTTPS certificate verification" msgstr "HTTPS 证书验证" #: sabnzbd/skintext.py msgid "" "Verify certificates when connecting to indexers and RSS-sources using HTTPS." msgstr "当用 HTTPS 方式连接索引和RSS源时验证证书。" #: sabnzbd/skintext.py msgid "Server" msgstr "服务器" #: sabnzbd/skintext.py msgid "Post processing" msgstr "后期处理" #: sabnzbd/skintext.py msgid "Naming" msgstr "命名" #: sabnzbd/skintext.py msgid "Quota" msgstr "配额" #: sabnzbd/skintext.py msgid "Indexing" msgstr "正在索引" #: sabnzbd/skintext.py msgid "How much can be downloaded this month (K/M/G)" msgstr "本月能下载多少数据量 (K/M/G)" #: sabnzbd/skintext.py [Reset day of the download quota] msgid "Reset day" msgstr "重置时间" #: sabnzbd/skintext.py msgid "" "On which day of the month or week (1=Monday) does your ISP reset the quota? " "(Optionally with hh:mm)" msgstr "您的 ISP 会在每月或每周的哪天 (1=星期一) 重置配额? (可选加上 hh:mm)" #: sabnzbd/skintext.py [Auto-resume download on the reset day] msgid "Auto resume" msgstr "自动续传" #: sabnzbd/skintext.py msgid "Should downloading resume after the quota is reset?" msgstr "配额重置后是否自动续传下载?" #: sabnzbd/skintext.py [Does the quota get reset every day, week or month?] msgid "Quota period" msgstr "配额周期" #: sabnzbd/skintext.py msgid "Does the quota get reset each day, week or month?" msgstr "配额会每天、每周或每月重置吗?" #: sabnzbd/skintext.py msgid "Check before download" msgstr "下载前检查" #: sabnzbd/skintext.py msgid "Try to predict successful completion before actual download (slower!)" msgstr "在实际下载之前尝试预测可以成功下载的完整程度 (会减慢下载进度!)" #: sabnzbd/skintext.py msgid "SSL Ciphers" msgstr "SSL 加密算法" #: sabnzbd/skintext.py msgid "Increase performance by forcing a lower SSL encryption strength." msgstr "降低 SSL 的加密难度以便获得更高的性能。" #: sabnzbd/skintext.py # sabnzbd/urlgrabber.py msgid "Maximum retries" msgstr "最多重试次数" #: sabnzbd/skintext.py msgid "Maximum number of retries per server" msgstr "各服务器重试的最多次数" #: sabnzbd/skintext.py msgid "Abort jobs that cannot be completed" msgstr "中止无法完成的任务" #: sabnzbd/skintext.py msgid "" "When during download it becomes clear that too much data is missing, abort " "the job" msgstr "下载时若发现缺失数据过多,则中止对应任务" #: sabnzbd/skintext.py msgid "Enable Indexer Integration" msgstr "启用索引集成" #: sabnzbd/skintext.py msgid "" "Indexers can supply rating information when a job is added and SABnzbd can " "report to the indexer if a job couldn't be completed." msgstr "" #: sabnzbd/skintext.py msgid "Enable Filtering" msgstr "启用过滤" #: sabnzbd/skintext.py msgid "Action downloads according to filtering rules." msgstr "根据过滤规则对下载任务执行操作" #: sabnzbd/skintext.py msgid "Abort If" msgstr "中止的条件" #: sabnzbd/skintext.py msgid "Else Pause If" msgstr "否则暂停的条件" #: sabnzbd/skintext.py msgid "Video rating" msgstr "视频评分" #: sabnzbd/skintext.py msgid "Audio rating" msgstr "音频评分" #: sabnzbd/skintext.py msgid "Spam" msgstr "垃圾" #: sabnzbd/skintext.py msgid "Confirmed" msgstr "已确认" #: sabnzbd/skintext.py msgid "More thumbs down than up" msgstr "缩略图的减分比加分多" #: sabnzbd/skintext.py msgid "Title keywords" msgstr "标题关键词" #: sabnzbd/skintext.py msgid "Comma separated list" msgstr "逗号分隔的列表" #: sabnzbd/skintext.py msgid "Server load-balancing" msgstr "服务器负载均衡" #: sabnzbd/skintext.py msgid "Prevent load-balancing" msgstr "避免负载均衡" #: sabnzbd/skintext.py msgid "Allow load-balancing" msgstr "允许负载均衡" #: sabnzbd/skintext.py msgid "Allow load-balancing with optimization for IPv6" msgstr "允许负载均衡,并对 IPv6 优化" #: sabnzbd/skintext.py msgid "Useful if a newsserver has more than one IPv4/IPv6 address" msgstr "如果新闻服务器有多个 IPv4/IPv6 地址将非常有用" #: sabnzbd/skintext.py [Caption] # sabnzbd/skintext.py [Button: Add server] msgid "Add Server" msgstr "添加服务器" #: sabnzbd/skintext.py [User defined name for server] msgid "Server description" msgstr "服务器描述" #: sabnzbd/skintext.py [Server port] msgid "Port" msgstr "端口" #: sabnzbd/skintext.py [Server username] msgid "Username" msgstr "用户名" #: sabnzbd/skintext.py [Server password] msgid "Password" msgstr "密码" #: sabnzbd/skintext.py [Server timeout] msgid "Timeout" msgstr "超时" #: sabnzbd/skintext.py [Server's retention time in days] msgid "Retention time" msgstr "保存期限" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "SSL" msgstr "SSL" #: sabnzbd/skintext.py [Server SSL tickbox] msgid "Secure connection to server" msgstr "到服务器的安全连接" #: sabnzbd/skintext.py msgid "Certificate verification" msgstr "证书验证" #: sabnzbd/skintext.py msgid "" "Minimal: when SSL is enabled, verify the identity of the server using its " "certificates. Strict: verify and enforce matching hostname." msgstr "最小:启动 SSL 时,使用服务器自己的证书来验证身份。严格:验证并强制 hostname 一致。" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Disabled" msgstr "禁用" #: sabnzbd/skintext.py msgid "Minimal" msgstr "最小" #: sabnzbd/skintext.py msgid "Strict" msgstr "严格" #: sabnzbd/skintext.py [Explain server priority] msgid "0 is highest priority, 100 is the lowest priority" msgstr "0 为最高优先级,100 为最低优先级" #: sabnzbd/skintext.py [Server optional tickbox] msgid "Optional" msgstr "可选" #: sabnzbd/skintext.py [Explain server optional tickbox] msgid "For unreliable servers, will be ignored longer in case of failures" msgstr "对于不稳定的服务器,在失败后将会被忽略更长的时间" #: sabnzbd/skintext.py [Enable server tickbox] msgid "Enable" msgstr "启用" #: sabnzbd/skintext.py [Button: Remove server] msgid "Remove Server" msgstr "移除服务器" #: sabnzbd/skintext.py [Button: Test server] # sabnzbd/skintext.py [Wizard step] msgid "Test Server" msgstr "测试服务器" #: sabnzbd/skintext.py [Button: Clear server's byte counters] msgid "Clear Counters" msgstr "清除统计" #: sabnzbd/skintext.py msgid "Testing server details..." msgstr "正在测试服务器详细情况..." #: sabnzbd/skintext.py msgid "Bandwidth" msgstr "带宽" #: sabnzbd/skintext.py msgid "Send Group" msgstr "发送 Group 命令" #: sabnzbd/skintext.py msgid "Send group command before requesting articles." msgstr "请求文章之前发送 group 命令。" #: sabnzbd/skintext.py msgid "Only use this server for these categories." msgstr "只为这些分类使用该服务器。" #: sabnzbd/skintext.py msgid "" "None of the enabled servers have the 'Default' category selected. Jobs in " "the queue that are not assigned to one of the server's categories will not " "be downloaded." msgstr "已启用的服务器均未选择“默认”分类。队列中未分配到服务器对应分类的任务不会开始下载。" #: sabnzbd/skintext.py msgid "Personal notes" msgstr "注释" #: sabnzbd/skintext.py [Config->Scheduling] # sabnzbd/skintext.py [Config->Scheduling] msgid "Add Schedule" msgstr "添加定时任务" #: sabnzbd/skintext.py [Config->Scheduling] msgid "Current Schedules" msgstr "当前定时任务" #: sabnzbd/skintext.py msgid "" "The checkbox next to the feed name should be ticked for the feed to be " "enabled and be automatically checked for new items.
When a feed is " "added, it will only pick up new items and not anything already in the RSS " "feed unless you press \"Force Download\"." msgstr "" "需要勾选 feed 名称旁边的复选框才能启用并自动检查新项。
添加 feed 后,它将只选取新项目,而不选取已经处于 RSS feed " "当中的项,除非您按“强制下载”。" #: sabnzbd/skintext.py [Config->RSS, placeholder (cannot be too long)] msgid "Seperate multiple URLs by a comma" msgstr "以逗号来分开多个链接" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read Feed" msgstr "读取 Feed" #: sabnzbd/skintext.py [Config->RSS button] msgid "Force Download" msgstr "强制下载" #: sabnzbd/skintext.py [Config->RSS table column header] msgid "Filter" msgstr "过滤器" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Accept" msgstr "接受" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Reject" msgstr "否决" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "Requires" msgstr "需要" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "RequiresCat" msgstr "需要分类" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At least" msgstr "至少" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu] msgid "At most" msgstr "至多" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"] msgid "From SxxEyy" msgstr "来自 SxxEyy" #: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"] msgid "From Show SxxEyy" msgstr "来自剧目 SxxEyy" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Matched" msgstr "已匹配" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Not Matched" msgstr "未匹配" #: sabnzbd/skintext.py [Config->RSS section header] msgid "Downloaded" msgstr "已下载" #: sabnzbd/skintext.py [Config->RSS button] msgid "Read All Feeds Now" msgstr "立即读取全部 Feed" #: sabnzbd/skintext.py msgid "Email Notification On Job Completion" msgstr "任务完成 Email 通知" #: sabnzbd/skintext.py [When to send email] msgid "Never" msgstr "从不" #: sabnzbd/skintext.py [When to send email] msgid "Always" msgstr "总是" #: sabnzbd/skintext.py [When to send email] msgid "Error-only" msgstr "仅当发生错误时" #: sabnzbd/skintext.py msgid "Disk Full Notifications" msgstr "磁盘已满通知" #: sabnzbd/skintext.py msgid "Send email when disk is full and SABnzbd is paused." msgstr "磁盘已满、SABnzbd 暂停时发送 email。" #: sabnzbd/skintext.py msgid "Send RSS notifications" msgstr "发送 RSS 通知" #: sabnzbd/skintext.py msgid "Send email when an RSS feed adds jobs to the queue." msgstr "RSS feed 添加任务到队列时发送 email。" #: sabnzbd/skintext.py msgid "SMTP Server" msgstr "SMTP 服务器" #: sabnzbd/skintext.py msgid "Set your ISP's server for outgoing email." msgstr "设为您 ISP 的 email 出站服务器。" #: sabnzbd/skintext.py msgid "Email Recipient" msgstr "Email 收件者" #: sabnzbd/skintext.py msgid "Email address to send the email to." msgstr "发送 email 的目标电子邮箱地址。" #: sabnzbd/skintext.py msgid "Email Sender" msgstr "Email 发送者" #: sabnzbd/skintext.py msgid "Who should we say sent the email?" msgstr "我们应该说是谁发送了这封 email?" #: sabnzbd/skintext.py msgid "OPTIONAL Account Username" msgstr "*可选* 账号用户名" #: sabnzbd/skintext.py msgid "For authenticated email, account name." msgstr "email 身份认证所用的账号名称。" #: sabnzbd/skintext.py msgid "OPTIONAL Account Password" msgstr "*可选* 账号密码" #: sabnzbd/skintext.py msgid "For authenticated email, password." msgstr "email 身份认证所用的密码。" #: sabnzbd/skintext.py [Header Growl section] msgid "Growl" msgstr "Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Enable Growl" msgstr "启用 Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Send notifications to Growl" msgstr "将通知发送到 Growl" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Only use for remote Growl server (host:port)" msgstr "仅当使用远程 Growl 服务器时需要 (主机:端口)" #: sabnzbd/skintext.py [Growl server password] msgid "Server password" msgstr "服务器密码" #: sabnzbd/skintext.py [Don't translate "Growl"] msgid "Optional password for Growl server" msgstr "Growl 服务器可选密码" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Enable NotifyOSD" msgstr "启用NotifyOSD" #: sabnzbd/skintext.py [Don't translate "NotifyOSD"] msgid "Send notifications to NotifyOSD" msgstr "将通知发送到 NotifyOSD" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Header for OSX Notfication Center section] msgid "Notification Center" msgstr "通知中心" #: sabnzbd/skintext.py msgid "Send notifications to Notification Center" msgstr "将通知发送到“通知中心”" #: sabnzbd/skintext.py msgid "Enable Windows Notifications" msgstr "启用 Windows 通知" #: sabnzbd/skintext.py msgid "Windows Notifications" msgstr "Windows" #: sabnzbd/skintext.py [Header for Ubuntu's NotifyOSD notifications section] msgid "NotifyOSD" msgstr "屏显通知" #: sabnzbd/skintext.py [Header for Prowl notification section] msgid "Prowl" msgstr "Prowl" #: sabnzbd/skintext.py [Prowl settings] msgid "Enable Prowl notifications" msgstr "启用 Prowl 通知" #: sabnzbd/skintext.py [Prowl settings] msgid "Requires a Prowl account" msgstr "需要 Prowl 账号" #: sabnzbd/skintext.py [Prowl settings] msgid "API key for Prowl" msgstr "Prowl 的 API 密钥" #: sabnzbd/skintext.py [Prowl settings] msgid "Personal API key for Prowl (required)" msgstr "Prowl 的个人 API 密钥 (必填)" #: sabnzbd/skintext.py [Header for Pushover notification section] msgid "Pushover" msgstr "Pushover" #: sabnzbd/skintext.py [Pushover settings] msgid "Enable Pushover notifications" msgstr "启用 Pushover 通知" #: sabnzbd/skintext.py [Pushoversettings] msgid "Requires a Pushover account" msgstr "需要 Pushover 账号" #: sabnzbd/skintext.py [Pushover settings] msgid "Application Token" msgstr "应用程序 token" #: sabnzbd/skintext.py [Pushover settings] msgid "Application token (required)" msgstr "应用程序令牌 (必填)" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key" msgstr "用户 key" #: sabnzbd/skintext.py [Pushover settings] msgid "User Key (required)" msgstr "用户密钥 (必填)" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s)" msgstr "设备" #: sabnzbd/skintext.py [Pushover settings] msgid "Device(s) to which message should be sent" msgstr "信息发送的目标设备" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency retry" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How often (in seconds) the same notification will be sent" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "Emergency expire" msgstr "" #: sabnzbd/skintext.py [Pushover settings] msgid "How many seconds your notification will continue to be retried" msgstr "" #: sabnzbd/skintext.py [Header for Pushbullet notification section] msgid "Pushbullet" msgstr "Pushbullet" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Enable Pushbullet notifications" msgstr "启用 Pushbullet 通知" #: sabnzbd/skintext.py [Pushbulletsettings] msgid "Requires a Pushbullet account" msgstr "需要 Pushbullet 账号" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Personal API key" msgstr "个人 API key" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Your personal Pushbullet API key (required)" msgstr "您自己的 Pushbullet API key (必填)" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device" msgstr "设备" #: sabnzbd/skintext.py [Pushbullet settings] msgid "Device to which message should be sent" msgstr "信息发送的目标设备" #: sabnzbd/skintext.py [Header for Notification Script notification section] msgid "Notification Script" msgstr "通知脚本" #: sabnzbd/skintext.py [Notification Script settings] msgid "Enable notification script" msgstr "启用通知脚本" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Executes a custom script" msgstr "执行自定义脚本" #: sabnzbd/skintext.py [Notification Scriptsettings] msgid "Which script should we execute for notification?" msgstr "应该执行哪个脚本来发出通知?" #: sabnzbd/skintext.py msgid "" "Indexers can supply a category inside the NZB which SABnzbd will try to " "match to the categories defined below. Additionally, you can add terms to " "\"Indexer Categories / Groups\" to match more categories. Use commas to " "separate terms. Wildcards in the terms are supported.
More information " "can be found on the Wiki." msgstr "" "索引可以在 NZB 文件中提供分类信息,SABnzbd 会尝试在以下分类中匹配。另外,您可以在 \"索引 Categories / Groups\" " "中添加关键词来匹配更多的分类。使用逗号来分开关键词,关键词中可使用通配符。
你可以在维基中查看更多的相关信息。" #: sabnzbd/skintext.py msgid "" "Ending the path with an asterisk * will prevent creation of job folders." msgstr "路径末尾加上星号 * 可避免创建任务文件夹。" #: sabnzbd/skintext.py msgid "Relative folders are based on" msgstr "基于相对文件夹" #: sabnzbd/skintext.py msgid "Folder/Path" msgstr "文件夹/路径" #: sabnzbd/skintext.py msgid "Indexer Categories / Groups" msgstr "索引 Categories / Groups" #: sabnzbd/skintext.py [Small delete button] msgid "X" msgstr "X" #: sabnzbd/skintext.py msgid "Series Sorting" msgstr "TV 排序" #: sabnzbd/skintext.py msgid "Enable TV Sorting" msgstr "启用 TV 排序" #: sabnzbd/skintext.py msgid "Pattern Key" msgstr "匹配符释义" #: sabnzbd/skintext.py msgid "Clear" msgstr "清除" #: sabnzbd/skintext.py msgid "Apply filters" msgstr "应用过滤器" #: sabnzbd/skintext.py msgid "Presets" msgstr "预设" #: sabnzbd/skintext.py msgid "Example" msgstr "示例" #: sabnzbd/skintext.py msgid "Movie Sorting" msgstr "电影排序" #: sabnzbd/skintext.py msgid "Enable Movie Sorting" msgstr "启用电影排序" #: sabnzbd/skintext.py msgid "Keep loose downloads in extra folders" msgstr "将下载内容保留在额外文件夹" #: sabnzbd/skintext.py msgid "Affected Categories" msgstr "影响分类" #: sabnzbd/skintext.py msgid "Meaning" msgstr "释义" #: sabnzbd/skintext.py msgid "Pattern" msgstr "匹配" #: sabnzbd/skintext.py msgid "Result" msgstr "结果" #: sabnzbd/skintext.py msgid "1x05 Season Folder" msgstr "1x05 季度文件夹" #: sabnzbd/skintext.py msgid "S01E05 Season Folder" msgstr "S01E05 季度文件夹" #: sabnzbd/skintext.py msgid "1x05 Episode Folder" msgstr "1x05 剧集文件夹" #: sabnzbd/skintext.py msgid "S01E05 Episode Folder" msgstr "S01E05 剧集文件夹" #: sabnzbd/skintext.py msgid "Job Name as Filename" msgstr "" #: sabnzbd/skintext.py msgid "Title" msgstr "标题" #: sabnzbd/skintext.py msgid "Movie Name" msgstr "影片 名称" #: sabnzbd/skintext.py msgid "Movie.Name" msgstr "影片.名称" #: sabnzbd/skintext.py msgid "Movie_Name" msgstr "影片_名称" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Show Name" msgstr "节目 名称" #: sabnzbd/skintext.py msgid "Show.Name" msgstr "节目.名称" #: sabnzbd/skintext.py msgid "Show_Name" msgstr "节目_名称" #: sabnzbd/skintext.py msgid "Season Number" msgstr "季数" #: sabnzbd/skintext.py msgid "Episode Number" msgstr "集数" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Episode Name" msgstr "集 名" #: sabnzbd/skintext.py msgid "Episode.Name" msgstr "集.名" #: sabnzbd/skintext.py msgid "Episode_Name" msgstr "集_名" #: sabnzbd/skintext.py msgid "File Extension" msgstr "文件扩展名" #: sabnzbd/skintext.py msgid "Extension" msgstr "扩展名" #: sabnzbd/skintext.py msgid "Part Number" msgstr "分段号" #: sabnzbd/skintext.py msgid "Decade" msgstr "年代" #: sabnzbd/skintext.py msgid "Original Filename" msgstr "原始文件名" #: sabnzbd/skintext.py msgid "Original Job Name" msgstr "" #: sabnzbd/skintext.py msgid "Lower Case" msgstr "大小写" #: sabnzbd/skintext.py msgid "TEXT" msgstr "TEXT" #: sabnzbd/skintext.py msgid "text" msgstr "text" #: sabnzbd/skintext.py msgid "file" msgstr "文件" #: sabnzbd/skintext.py msgid "Sort String" msgstr "排序字串" #: sabnzbd/skintext.py msgid "Multi-part label" msgstr "多段标记" #: sabnzbd/skintext.py msgid "In folders" msgstr "分文件夹" #: sabnzbd/skintext.py msgid "No folders" msgstr "不分文件夹" #: sabnzbd/skintext.py msgid "Date Sorting" msgstr "日期排序" #: sabnzbd/skintext.py msgid "Enable Date Sorting" msgstr "启用日期排序" #: sabnzbd/skintext.py msgid "Show Name folder" msgstr "节目名称文件夹" #: sabnzbd/skintext.py msgid "Year-Month Folders" msgstr "年-月文件夹" #: sabnzbd/skintext.py msgid "Daily Folders" msgstr "每天文件夹" #: sabnzbd/skintext.py [Note for title expression in Sorting that does case adjustment] msgid "case-adjusted" msgstr "大小写已调整" #: sabnzbd/skintext.py msgid "Processed Result" msgstr "处理结果" #: sabnzbd/skintext.py msgid "" "Rarely used options. For their meaning and explanation, click on the Help " "button to go to the Wiki page.
Don't change these without checking the " "Wiki first, as some have serious side-effects.
The default values are " "between parentheses." msgstr "" "极少用到的选项。要获取其含义及解释,请点击“帮助”按钮访问 Wiki 页面。
在查看 Wiki " "之前请不要更改这些选项,它们会有很严重的副作用。
括号中为默认值。" #: sabnzbd/skintext.py msgid "Values" msgstr "值" #: sabnzbd/skintext.py [Job details page] msgid "Edit NZB Details" msgstr "编辑 NZB 详情" #: sabnzbd/skintext.py [Job details page, delete button] msgid "Delete" msgstr "删除" #: sabnzbd/skintext.py [Job details page, move file to top] # sabnzbd/skintext.py msgid "Top" msgstr "置顶" #: sabnzbd/skintext.py [Job details page, move file one place up] msgid "Up" msgstr "上移" #: sabnzbd/skintext.py [Job details page, move file one place down] msgid "Down" msgstr "下移" #: sabnzbd/skintext.py [Job details page, move file to bottom] # sabnzbd/skintext.py msgid "Bottom" msgstr "置底" #: sabnzbd/skintext.py [Job details page, select all files] msgid "All" msgstr "全部" #: sabnzbd/skintext.py [Job details page, invert file selection] msgid "Invert" msgstr "反选" #: sabnzbd/skintext.py [Job details page, filename column header] msgid "Filename" msgstr "文件名" #: sabnzbd/skintext.py [Job details page, subject column header] msgid "Subject" msgstr "主题" #: sabnzbd/skintext.py [Job details page, section header] msgid "Selection" msgstr "选择" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 5 minutes" msgstr "暂停 5 分钟" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 15 minutes" msgstr "暂停 15 分钟" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 30 minutes" msgstr "暂停 30 分钟" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 1 hour" msgstr "暂停 1 小时" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 3 hours" msgstr "暂停 3 小时" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for 6 hours" msgstr "暂停 6 小时" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "left" msgstr "剩余" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Free Space" msgstr "剩余空间" #: sabnzbd/skintext.py msgid "Temp Folder" msgstr "临时文件夹" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Multi-Operations" msgstr "多选操作" #: sabnzbd/skintext.py msgid "Hold shift key to select a range" msgstr "按 shift 键可选择范围" #: sabnzbd/skintext.py msgid "Check all" msgstr "全选" #: sabnzbd/skintext.py msgid "Restart SABnzbd" msgstr "重新启动 SABnzbd" #: sabnzbd/skintext.py msgid "Status and interface options" msgstr "状态与界面选项" #: sabnzbd/skintext.py msgid "Or drag and drop files in the window!" msgstr "或将文件拖拽到本窗口!" #: sabnzbd/skintext.py msgid "Lost connection to SABnzbd.." msgstr "失去与 SABnzbd 的连接.." #: sabnzbd/skintext.py msgid "In case of SABnzbd restart this screen will disappear automatically!" msgstr "SABnzbd 重启后本画面将自动消失!" #: sabnzbd/skintext.py msgid "WARNING:" msgstr "警告:" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box] msgid "Fetch" msgstr "装取" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh rate" msgstr "刷新频率" #: sabnzbd/skintext.py msgid "Use global interface settings" msgstr "使用全局界面设置" #: sabnzbd/skintext.py msgid "Queue item limit" msgstr "队列数目限制" #: sabnzbd/skintext.py msgid "History item limit" msgstr "历史数目限制" #: sabnzbd/skintext.py msgid "Date format" msgstr "日期格式" #: sabnzbd/skintext.py msgid "Extra queue column" msgstr "队列显示更多列" #: sabnzbd/skintext.py msgid "Extra history column" msgstr "额外的历史记录列" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "page" msgstr "页" #: sabnzbd/skintext.py msgid "Loading" msgstr "正在加载" #: sabnzbd/skintext.py msgid "articles" msgstr "篇文章" #: sabnzbd/skintext.py msgid "Rename" msgstr "重命名" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Queue repair" msgstr "队列修复" #: sabnzbd/skintext.py msgid "Show active connections" msgstr "显示活动连接" #: sabnzbd/skintext.py msgid "Orphaned jobs" msgstr "孤立任务" #: sabnzbd/skintext.py msgid "Send back to queue" msgstr "发回队列" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Delete All" msgstr "全部删除" #: sabnzbd/skintext.py # sabnzbd/skintext.py [Link in SMPL for "Retry all failed jobs"] msgid "Retry all" msgstr "全部重试" #: sabnzbd/skintext.py msgid "Fetch NZB from URL" msgstr "从 URL 装取 NZB" #: sabnzbd/skintext.py msgid "Upload NZB" msgstr "上传 NZB" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Optionally specify a filename" msgstr "可以选择指定文件名" #: sabnzbd/skintext.py msgid "Formats: .nzb, .rar, .zip, .gz, .bz2" msgstr "格式: .nzb, .rar, .zip, .gz, .bz2" #: sabnzbd/skintext.py msgid "Submit" msgstr "提交" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Open Informational URL" msgstr "打开信息 URL" #: sabnzbd/skintext.py msgid "Submitted. Thank you!" msgstr "已提交。感谢!" #: sabnzbd/skintext.py msgid "Nothing selected!" msgstr "未选择任何内容!" #: sabnzbd/skintext.py msgid "Remove all selected files" msgstr "移除已选文件" #: sabnzbd/skintext.py msgid "Hide/show completed files" msgstr "隐藏/显示已完成文件" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "View Script Log" msgstr "查看脚本日志" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Update Available!" msgstr "有更新可用!" #: sabnzbd/skintext.py [Don't translate LocalStorage] msgid "" "LocalStorage (cookies) are disabled in your browser, interface settings will " "be lost after you close the browser!" msgstr "您的浏览器已禁用 LocalStorage (cookies)。界面设置将在您关闭浏览器后丢失!" #: sabnzbd/skintext.py msgid "Glitter has some (new) features you might like!" msgstr "你可能会喜欢一些 Glitter 的(新)功能!" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Custom" msgstr "自定义" #: sabnzbd/skintext.py msgid "Compact layout" msgstr "精简外观" #: sabnzbd/skintext.py msgid "Tabbed layout
(separate queue and history)" msgstr "标签化外观
(分别显示队列与历史记录)" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Speed" msgstr "速度" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm Queue Deletions" msgstr "确认队列删除" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Confirm History Deletions" msgstr "确认历史删除" #: sabnzbd/skintext.py msgid "How long or untill when do you want to pause? (in English!)" msgstr "您希望在多久之后/什么时候暂停? (用英语作答!)" #: sabnzbd/skintext.py msgid "Sorry, we could not interpret that. Try again." msgstr "抱歉,无法理解您的输入。请重试。" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for..." msgstr "暂停..." #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Refresh" msgstr "刷新" #: sabnzbd/skintext.py msgid "" "All usernames, passwords and API-keys are automatically removed from the log " "and the included copy of your settings." msgstr "" #: sabnzbd/skintext.py msgid "Sort by Age Oldest→Newest" msgstr "按发布时间排序 最早→最新" #: sabnzbd/skintext.py msgid "Sort by Age Newest→Oldest" msgstr "按发布时间排序 最新→最早" #: sabnzbd/skintext.py msgid "Sort by Name A→Z" msgstr "按名称排序 A→Z" #: sabnzbd/skintext.py msgid "Sort by Name Z→A" msgstr "按名称排序 Z→A" #: sabnzbd/skintext.py msgid "Sort by Size Smallest→Largest" msgstr "按尺寸排序 最小→最大" #: sabnzbd/skintext.py msgid "Sort by Size Largest→Smallest" msgstr "按尺寸排序 最大→最小" #: sabnzbd/skintext.py msgid "Uploading" msgstr "正在上传" #: sabnzbd/skintext.py msgid "Forcing disconnect" msgstr "正在强制断开连接" #: sabnzbd/skintext.py msgid "Removing job" msgstr "正在移除任务" #: sabnzbd/skintext.py msgid "Removing jobs" msgstr "正在移除任务" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Prev" msgstr "前" #: sabnzbd/skintext.py # sabnzbd/skintext.py # sabnzbd/skintext.py [Button to go to next Wizard page] msgid "Next" msgstr "后" #: sabnzbd/skintext.py msgid "Purge the History?" msgstr "清空历史?" #: sabnzbd/skintext.py msgid "You must enable JavaScript for Plush to function!" msgstr "您必须启用 JavaScript 才能使用 Plush 模板!" #: sabnzbd/skintext.py msgid "Options" msgstr "选项" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Pause for how many minutes?" msgstr "暂停多少分钟?" #: sabnzbd/skintext.py msgid "Top Menu" msgstr "顶部菜单切换" #: sabnzbd/skintext.py msgid "On Finish" msgstr "完成时" #: sabnzbd/skintext.py msgid "Sort" msgstr "排序" #: sabnzbd/skintext.py msgid "Sort by Age (Oldest→Newest)" msgstr "按发布时间排列 (最早→最新)" #: sabnzbd/skintext.py msgid "Sort by Age (Newest→Oldest)" msgstr "按发布时间排列 (最新→最早)" #: sabnzbd/skintext.py msgid "Sort by Name (A→Z)" msgstr "按名称排列 (A→Z)" #: sabnzbd/skintext.py msgid "Sort by Name (Z→A)" msgstr "按名称排列 (Z→A)" #: sabnzbd/skintext.py msgid "Sort by Size (Smallest→Largest)" msgstr "按尺寸排列 (最小→最大)" #: sabnzbd/skintext.py msgid "Sort by Size (Largest→Smallest)" msgstr "按尺寸排列 (最大→最小)" #: sabnzbd/skintext.py msgid "Purge the Queue?" msgstr "清除队列?" #: sabnzbd/skintext.py msgid "Retry all failed jobs in History?" msgstr "重试“历史记录”中所有已失败任务?" #: sabnzbd/skintext.py msgid "Purge" msgstr "清理" #: sabnzbd/skintext.py [Used in speed menu. Split in two lines if too long.] msgid "Max Speed" msgstr "最高速度" #: sabnzbd/skintext.py msgid "Range" msgstr "范围" #: sabnzbd/skintext.py msgid "Apply to Selected" msgstr "应用到所选项" #: sabnzbd/skintext.py msgid "Everything" msgstr "全部" #: sabnzbd/skintext.py msgid "Refresh Rate" msgstr "刷新频率" #: sabnzbd/skintext.py msgid "Container Width" msgstr "容器宽度" #: sabnzbd/skintext.py msgid "" "This will prevent refreshing content when your mouse cursor is hovering over " "the queue." msgstr "这将在您的鼠标指针处于队列上方时阻止内容刷新。" #: sabnzbd/skintext.py msgid "Block Refreshes on Hover" msgstr "指向时停止刷新" #: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box] msgid "Upload" msgstr "上传" #: sabnzbd/skintext.py msgid "Upload: .nzb .rar .zip .gz, .bz2" msgstr "上传: .nzb .rar .zip .gz, .bz2" #: sabnzbd/skintext.py # sabnzbd/skintext.py msgid "Progress" msgstr "进度" #: sabnzbd/skintext.py msgid "Not enough disk space to complete downloads!" msgstr "磁盘空间不足以完成下载!" #: sabnzbd/skintext.py msgid "Free (Temp)" msgstr "剩余 (临时)" #: sabnzbd/skintext.py msgid "IDLE" msgstr "*空闲*" #: sabnzbd/skintext.py msgid "Downloads" msgstr "下载列表" #: sabnzbd/skintext.py msgid "Delete Completed" msgstr "删除完成项" #: sabnzbd/skintext.py msgid "Delete the all failed items from the history?" msgstr "从历史中删除所有失败项?" #: sabnzbd/skintext.py msgid "Delete Failed" msgstr "删除失败项" #: sabnzbd/skintext.py msgid "Retry all failed jobs?" msgstr "重试所有已失败任务?" #: sabnzbd/skintext.py msgid "Links" msgstr "链接" #: sabnzbd/skintext.py msgid "Showing %s to %s out of %s results" msgstr "正显示第 %s ~ %s 项结果,共 %s 项" #: sabnzbd/skintext.py msgid "No results" msgstr "无结果" #: sabnzbd/skintext.py msgid "Showing one result" msgstr "正显示一项结果" #: sabnzbd/skintext.py msgid "First" msgstr "首" #: sabnzbd/skintext.py msgid "Last" msgstr "末" #: sabnzbd/skintext.py msgid "Email Sent!" msgstr "邮件已发送!" #: sabnzbd/skintext.py msgid "Notification Sent!" msgstr "通知已发送!" #: sabnzbd/skintext.py msgid "Saving.." msgstr "正在保存.." #: sabnzbd/skintext.py msgid "Saved" msgstr "已保存" #: sabnzbd/skintext.py msgid "Toggle Add NZB" msgstr "切换新增 NZB" #: sabnzbd/skintext.py msgid "DualView1" msgstr "双视图1" #: sabnzbd/skintext.py msgid "DualView2" msgstr "双视图2" #: sabnzbd/skintext.py msgid "Are you sure you want to restart SABnzbd?" msgstr "是否确定要重新启动 SABnzbd?" #: sabnzbd/skintext.py msgid "Hide Edit Options" msgstr "隐藏编辑选项" #: sabnzbd/skintext.py msgid "Show Edit Options" msgstr "显示编辑选项" #: sabnzbd/skintext.py msgid "Edit" msgstr "编辑" #: sabnzbd/skintext.py msgid "Timeleft" msgstr "剩余时间" #: sabnzbd/skintext.py msgid "SABnzbd Quick-Start Wizard" msgstr "SABnzbd 快速上手向导" #: sabnzbd/skintext.py msgid "SABnzbd Version" msgstr "SABnzbd 版本" #: sabnzbd/skintext.py [Button to go to previous Wizard page] msgid "Previous" msgstr "上一步" #: sabnzbd/skintext.py msgid "Server Details" msgstr "服务器详情" #: sabnzbd/skintext.py msgid "Please enter in the details of your primary usenet provider." msgstr "请输入您的主 usenet 提供商的详细信息。" #: sabnzbd/skintext.py msgid "The number of connections allowed by your provider" msgstr "提供商所允许的连接数" #: sabnzbd/skintext.py [Wizard: examples of amount of connections] msgid "E.g. 8 or 20" msgstr "如 8 或 20" #: sabnzbd/skintext.py msgid "Select only if your provider allows SSL connections." msgstr "仅当您的服务商允许 SSL 连接时选择。" #: sabnzbd/skintext.py msgid "Click to test the entered details." msgstr "点击可测试所输入的信息。" #: sabnzbd/skintext.py [Abbreviation for "for example"] msgid "E.g." msgstr "如" #: sabnzbd/skintext.py [Wizard step] msgid "Setup is now complete!" msgstr "设置完成!" #: sabnzbd/skintext.py [Wizard tip] msgid "SABnzbd will now be running in the background." msgstr "SABnzbd 将在后台运行。" #: sabnzbd/skintext.py [Wizard tip] msgid "Closing any browser windows/tabs will NOT close SABnzbd." msgstr "关闭浏览器窗口/标签页 *不会* 导致 SABnzbd 关闭。" #: sabnzbd/skintext.py [Wizard tip] msgid "" "It is recommended you right click and bookmark this location and use this " "bookmark to access SABnzbd when it is running in the background." msgstr "建议您右击鼠标并将该链接加入书签以便在 SABnzbd 在后台运行时访问它。" #: sabnzbd/skintext.py [Will be appended with a wiki-link, adjust word order accordingly] msgid "Further help can be found on our" msgstr "更详尽的帮助可以在我们的网站上找到" #: sabnzbd/skintext.py [Wizard step] msgid "Go to SABnzbd" msgstr "转到 SABnzbd" #: sabnzbd/skintext.py [Wizard EXIT button on first page] msgid "Exit SABnzbd" msgstr "退出 SABnzbd" #: sabnzbd/skintext.py [Wizard START button on first page] msgid "Start Wizard" msgstr "启动向导" #: sabnzbd/skintext.py msgid "" "\n" "SABnzbd comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it under certain " "conditions.\n" "It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your " "option) any later version.\n" msgstr "" "\n" "SABnzbd *不负任何担保责任*。\n" "这是一款自由软件,欢迎您在约定的条件下传播。\n" "本软件依 GNU GENERAL PUBLIC LICENSE 第 2 版或 (若您愿意) 任意较新版本授权。\n" #: sabnzbd/skintext.py msgid "" "In order to download from usenet you will require access to a provider. Your " "ISP may provide you with access, however a premium provider is recommended." msgstr "要从 usenet 下载您需要有一家提供商的访问权限。您的 ISP 可能会为您提供权限,但推荐您选用付费的高级提供商。" #: sabnzbd/skintext.py msgid "Don't have a usenet provider? We recommend trying %s." msgstr "还没有 usenet 提供商r? 我们推荐试试 %s。" #: sabnzbd/sorting.py [Error message] msgid "Error getting TV info (%s)" msgstr "获取 TV 信息出错 (%s)" #: sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] # sabnzbd/sorting.py [Error message] #: sabnzbd/sorting.py [Error message] msgid "Failed to rename: %s to %s" msgstr "重命名失败: %s 为 %s" #: sabnzbd/sorting.py [Error message] msgid "Failed to rename similar file: %s to %s" msgstr "重命名相似文件失败: %s 为 %s" #: sabnzbd/urlgrabber.py msgid "Server name does not resolve" msgstr "服务器名无法解析" #: sabnzbd/urlgrabber.py msgid "Unauthorized access" msgstr "未授权访问" #: sabnzbd/urlgrabber.py msgid "File not on server" msgstr "服务器上无此文件" #: sabnzbd/urlgrabber.py msgid "Server could not complete request" msgstr "服务器无法完成请求" #: sabnzbd/urlgrabber.py [Error message] msgid "URLGRABBER CRASHED" msgstr "*URLGRABBER 已崩溃*" #: sabnzbd/urlgrabber.py msgid "Unusable NZB file" msgstr "不可用的 NZB 文件" #: sabnzbd/urlgrabber.py # sabnzbd/urlgrabber.py msgid "URL Fetching failed; %s" msgstr "URL 装取失败; %s" #~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file" #~ msgstr "警告: 由于检测到加密的 RAR 文件,任务 \"%s\" 已暂停" #~ msgid "Folder \"%s\" does not exist" #~ msgstr "文件夹 \"%s\" 不存在" #~ msgid "SQL Commit Failed, see log" #~ msgstr "SQL 保存失败,参见日志" #~ msgid "CRC Error in %s (%s -> %s)" #~ msgstr "CRC 错误:%s (%s -> %s)" #~ msgid "Error: No secondary interface defined." #~ msgstr "错误: 未定义第二界面。" #~ msgid "" #~ "Your UNRAR version is not recommended, get it from " #~ "http://www.rarlab.com/rar_add.htm
" #~ msgstr "您的 UNRAR 程序不是推荐版本,请从 http://www.rarlab.com/rar_add.htm 获取
" #~ msgid "No UNRAR program found, unpacking RAR files is not possible
" #~ msgstr "未找到 UNRAR 程序,您将无法解压 RAR 文件
" #~ msgid "No PAR2 program found, repairs not possible
" #~ msgstr "未找到 PAR2 程序,您将无法执行修复操作
" #~ msgid "Initiating restart...
" #~ msgstr "正在初始化重启动作...
" #~ msgid "Job \"%s\" was re-added to the queue" #~ msgstr "任务 \"%s\" 已被重新添加到队列" #~ msgid "Jobs marked with a '*' will not be automatically downloaded." #~ msgstr "标记有 '*' 的任务不会自动下载。" #~ msgid "Not matched" #~ msgstr "未匹配" #~ msgid "Downloaded so far" #~ msgstr "已下载" #~ msgid "Cannot connect to registry hive HKEY_CURRENT_USER." #~ msgstr "无法连接到注册表配置单元 HKEY_CURRENT_USER。" #~ msgid "Cannot open registry key \"%s\"." #~ msgstr "无法打开注册表键 \"%s\"。" #~ msgid "Failed to read registry keys for special folders" #~ msgstr "无法读取特殊文件夹的注册表键" #~ msgid "Try again" #~ msgstr "重试" #~ msgid "pyopenssl module missing, please install for https access" #~ msgstr "缺 pyopenssl 模块,请安装该模块方可通过 https 访问" #~ msgid "Missing expected file: %s => unrar error?" #~ msgstr "缺预期文件: %s => unrar 错误?" #~ msgid "Unpacking failed, an expected file was not unpacked" #~ msgstr "解压失败,有预期文件未能解压" #~ msgid "Unpacking failed, these file(s) are missing:" #~ msgstr "解压失败,缺这些文件:" #~ msgid "Main packet not found..." #~ msgstr "主数据包未找到..." #~ msgid "Invalid par2 files, cannot verify or repair" #~ msgstr "par2 文件无效,无法验证或修复" #~ msgid "Error importing OpenSSL module. Connecting with NON-SSL" #~ msgstr "导入 OpenSSL 模块出错。正在通过非 SSL 连接" #~ msgid "" #~ "\n" #~ " SABnzbd is not compatible with some software firewalls.
\n" #~ " %s
\n" #~ " Sorry, but we cannot solve this incompatibility right now.
\n" #~ " Please file a complaint at your firewall supplier.
\n" #~ "
\n" #~ msgstr "" #~ "\n" #~ " SABnzbd 与部分软件防火墙不兼容。
\n" #~ " %s
\n" #~ " 抱歉,我们目前还无法解决这个不兼容的情况。
\n" #~ " 请咨询您的防火墙提供商。
\n" #~ "
\n" #~ msgid "" #~ "\n" #~ " SABnzbd needs a free tcp/ip port for its internal web server.
\n" #~ " Port %s on %s was tried , but the account used for SABnzbd has no " #~ "permission to use it.
\n" #~ " On OSX and Linux systems, normal users must use ports above 1023.
\n" #~ "
\n" #~ " Please restart SABnzbd with a different port number." #~ msgstr "" #~ "\n" #~ " SABnzbd 的内部 web 服务器需要一个空闲的 tcp/ip 端口。
\n" #~ " 已尝试端口 %s(位于 %s),但 SABnzbd 所用账号没有权限使用该端口。
\n" #~ " 在 OSX 与 Linux 系统中,普通用户只能使用大于 1023 的端口。
\n" #~ "
\n" #~ " 请使用其他端口号重启 SABnzbd。" #~ msgid "OK" #~ msgstr "确定" #~ msgid "It is likely that you are using ZoneAlarm on Vista.
" #~ msgstr "您似乎处于 Vista 平台并且使用了 ZoneAlarm。
" #~ msgid "You have no permisson to use port %s" #~ msgstr "您没有权限使用端口 %s" #~ msgid "Failed to remove nzo from postproc queue (id)" #~ msgstr "无法从后期处理队列移除 nzo (id)" #~ msgid "View script output" #~ msgstr "查看脚本输出" #~ msgid "Get NZB" #~ msgstr "获取 NZB" #~ msgid "KB/s" #~ msgstr "KB/s" #~ msgid "Queued" #~ msgstr "在队列中" #~ msgid "Complete Dir" #~ msgstr "完成目录" #~ msgid "Download speed" #~ msgstr "下载速度" #~ msgid "Add new downloads" #~ msgstr "新增下载" #~ msgid " " #~ msgstr " " #~ msgid " or Report ID" #~ msgstr " 或报告 ID" #~ msgid "Sort by name" #~ msgstr "按名称排列" #~ msgid "Sort by age" #~ msgstr "按发布时间排列" #~ msgid "Sort by size" #~ msgstr "按尺寸排列" #~ msgid "Hide files" #~ msgstr "隐藏文件列表" #~ msgid "Show files" #~ msgstr "显示文件列表" #~ msgid "Remain/Total" #~ msgstr "剩余/总计" #~ msgid "Purge Failed History" #~ msgstr "清除失败历史" #~ msgid "Delete all failed items from History?" #~ msgstr "从“历史”中删除所有失败项?" #~ msgid "History Size" #~ msgstr "历史尺寸" #~ msgid "Show Weblogging" #~ msgstr "显示 web 日志" #~ msgid "Thread" #~ msgstr "线程" #~ msgid "Email Test Result" #~ msgstr "电子邮件测试结果" #~ msgid "General configuration" #~ msgstr "常规配置" #~ msgid "Secondary Web Interface" #~ msgstr "第二 Web 界面" #~ msgid "Activate an alternative skin." #~ msgstr "激活备选皮肤。" #~ msgid "Web server authentication" #~ msgstr "Web 服务器身份验证" #~ msgid "HTTPS Support" #~ msgstr "HTTPS 支持" #~ msgid "Queue auto refresh interval:" #~ msgstr "队列自动刷新间隔:" #~ msgid "Refresh interval of the queue web-interface page(sec, 0= none)." #~ msgstr "队列 web 界面页面的刷新间隔 (秒,0 = 不刷新)。" #~ msgid "Disable API-key" #~ msgstr "禁用 API-key" #~ msgid "Do not require the API key." #~ msgstr "不要求提供 API key。" #~ msgid "USE AT YOUR OWN RISK!" #~ msgstr "*后果自负!*" #~ msgid "QR Code" #~ msgstr "QR 码" #~ msgid "Folder configuration" #~ msgstr "文件夹配置" #~ msgid "Post-Processing Scripts Folder" #~ msgstr "后期处理脚本文件夹" #~ msgid "Folder containing user scripts for post-processing." #~ msgstr "包含后期处理用户脚本的文件夹。" #~ msgid "Switches configuration" #~ msgstr "参数配置" #~ msgid "Processing Switches" #~ msgstr "处理参数" #~ msgid "Enable Quick Check" #~ msgstr "启用快速检查" #~ msgid "Skip par2 checking when files are 100% valid." #~ msgstr "文件 100% 完好时跳过 par2 检查。" #~ msgid "Enable Unrar" #~ msgstr "启用 Unrar" #~ msgid "Enable built-in unrar functionality." #~ msgstr "启用内置 unrar 功能。" #~ msgid "Enable built-in unzip functionality." #~ msgstr "启用内置 unzip 功能。" #~ msgid "Enable Filejoin" #~ msgstr "启用文件合并" #~ msgid "Join files ending in .001, .002 etc. into one file." #~ msgstr "将 .001、.002 等结尾的文件合并为一个文件。" #~ msgid "Enable TS Joining" #~ msgstr "启用 TS 合并" #~ msgid "Join files ending in .001.ts, .002.ts etc. into one file." #~ msgstr "将 .001.ts、.002.ts 等结尾的文件合并为一个文件。" #~ msgid "Enable Par Cleanup" #~ msgstr "启用 Par 清理" #~ msgid "Cleanup par files (if verifiying/repairing succeded)." #~ msgstr "清理 par 文件 (若验证/修复成功)。" #~ msgid "Fail on yEnc CRC Errors" #~ msgstr "yEnc CRC 错误时重试" #~ msgid "When article has a CRC error, try to get it from another server." #~ msgstr "文章存在 CRC 错误时,尝试从其他服务器获取。" #~ msgid "Check result of unpacking" #~ msgstr "检查解压结果" #~ msgid "Check result of unpacking (needs to be off for some file systems)." #~ msgstr "检查解压结果 (部分文件系统需要关闭)。" #~ msgid "Default Post-Processing" #~ msgstr "默认后期处理" #~ msgid "Used when no post-processing is defined by the category." #~ msgstr "当分类未定义后期处理选项时使用。" #~ msgid "Default User Script" #~ msgstr "默认用户脚本" #~ msgid "Used when no user script is defined by the category." #~ msgstr "当分类未定义用户脚本时使用。" #~ msgid "Default Priority" #~ msgstr "默认优先级" #~ msgid "Used when no priority is defined by the category." #~ msgstr "当分类未定义优先级时使用。" #~ msgid "Enable MultiCore Par2" #~ msgstr "启用多核 Par2" #~ msgid "Other Switches" #~ msgstr "其他参数" #~ msgid "Replace Illegal Characters in Folder Names" #~ msgstr "替换成文件夹名称中的非法字符" #~ msgid "" #~ "Replace illegal characters in folder names by equivalents (otherwise remove)." #~ msgstr "将文件夹名称中的非法字符替换为等价字符 (不选则直接移除)。" #~ msgid "Do not download" #~ msgstr "不要下载" #~ msgid "SSL type" #~ msgstr "SSL 类型" #~ msgid "Use V23 unless your provider requires otherwise!" #~ msgstr "除非您的提供商要求选择其他类型,请使用 V23!" #~ msgid "Use 12 hour clock (AM/PM)" #~ msgstr "使用 12 小时制时钟 (AM/PM)" #~ msgid "Show times in AM/PM notation (does not affect scheduler)." #~ msgstr "以 AM/PM 记法显示时间 (不影响定时任务)。" #~ msgid "Only for optional servers" #~ msgstr "仅应用到可选服务器" #~ msgid "Apply maximum retries only to optional servers" #~ msgstr "只对可选服务器应用最多重试次数限制" #~ msgid "Server configuration" #~ msgstr "服务器配置" #~ msgid "Server definition" #~ msgstr "服务器定义" #~ msgid "Backup server" #~ msgstr "备份服务器" #~ msgid "Click below to test." #~ msgstr "点击下面的按钮开始测试。" #~ msgid "Scheduling configuration" #~ msgstr "定时任务配置" #~ msgid "Remove" #~ msgstr "移除" #~ msgid "RSS Configuration" #~ msgstr "RSS 配置" #~ msgid "New Feed URL" #~ msgstr "新 Feed URL" #~ msgid "Add Feed" #~ msgstr "添加 Feed" #~ msgid "Delete Feed" #~ msgstr "删除 Feed" #~ msgid "Skip" #~ msgstr "跳过" #~ msgid "Feeds" #~ msgstr "Feed 列表" #~ msgid "Settings" #~ msgstr "设置" #~ msgid "Filters" #~ msgstr "过滤器" #~ msgid "Email Options" #~ msgstr "Email 选项" #~ msgid "Email Account Settings" #~ msgstr "Email 账号设置" #~ msgid "User-defined categories" #~ msgstr "用户定义的分类" #~ msgid "Defines post-processing and storage." #~ msgstr "定义后期处理及存储行为。" #~ msgid "Groups / Indexer tags" #~ msgstr "群组 / 索引标记" #~ msgid "Sorting configuration" #~ msgstr "排序配置" #~ msgid "Enable sorting and renaming of episodes." #~ msgstr "启用排序及剧集重命名。" #~ msgid "Generic Sorting" #~ msgstr "通用排序" #~ msgid "Enable generic sorting and renaming of files." #~ msgstr "启用通用排序及文件重命名。" #~ msgid "Enable if downloads are not put in their own folders." #~ msgstr "启用可将下载内容存放在各自的文件夹。" #~ msgid "Original Foldername" #~ msgstr "原始文件夹名" #~ msgid "folder" #~ msgstr "文件夹" #~ msgid "Enable sorting and renaming of date named files." #~ msgstr "启用按日期命名的文件的排序与重命名。" #~ msgid "Are you sure you want to delete" #~ msgstr "是否确定要删除" #~ msgid "Page" #~ msgstr "页面" #~ msgid "Close" #~ msgstr "关闭" #~ msgid "Set Pause Interval" #~ msgstr "设置暂停间隔" #~ msgid "Pause Interval" #~ msgstr "暂停间隔" #~ msgid "Pause for 12 hours" #~ msgstr "暂停 12 小时" #~ msgid "Pause for 24 hours" #~ msgstr "暂停 24 小时" #~ msgid "Left" #~ msgstr "剩余" #~ msgid "Open Source URL" #~ msgstr "打开来源 URL" #~ msgid "Storage" #~ msgstr "存储" #~ msgid "Plush Options" #~ msgstr "Plush 选项" #~ msgid "Upload: .nzb .rar .zip .gz" #~ msgstr "上传: .nzb .rar .zip .gz" #~ msgid "" #~ "Read Feed will get the current feed content. Force " #~ "Download will download all matching NZBs now." #~ msgstr "" #~ "读取 Feed 将获取当前 feed 内容。强制下载 将立即下载全部匹配的 NZB。" #~ msgid "Hour:Min" #~ msgstr "小时:分钟" #~ msgid "Access" #~ msgstr "访问" #~ msgid "I want SABnzbd to be viewable by any pc on my network." #~ msgstr "我希望 SABnzbd 在所处网络的任意电脑中可见。" #~ msgid "I want SABnzbd to be viewable from my pc only." #~ msgstr "我希望 SABnzbd 只能在我自己的电脑中可见。" #~ msgid "Password protect access to SABnzbd (recommended)" #~ msgstr "SABnzbd 访问密码保护 (推荐)" #~ msgid "Enable HTTPS access to SABnzbd." #~ msgstr "启用 SABnzbd 的 HTTPS 访问。" #~ msgid "Misc" #~ msgstr "杂项" #~ msgid "" #~ "Launch my internet browser with the SABnzbd page when the program starts." #~ msgstr "程序启动时启动互联网浏览器打开 SABnzbd 页面。" #~ msgid "This field is required." #~ msgstr "该字段必填。" #~ msgid "Please enter a whole number." #~ msgstr "请输入整数。" #~ msgid "" #~ "After SABnzbd has finished restarting you will be able to access it at the " #~ "following location: %s" #~ msgstr "SABnzbd 完成重启后您可以在下面的位置访问它: %s" #~ msgid "Step One" #~ msgstr "第一步" #~ msgid "Step Two" #~ msgstr "第二步" #~ msgid "Step Three" #~ msgstr "第三步" #~ msgid "Step Four" #~ msgstr "第四步" #~ msgid "Step Five" #~ msgstr "第五步" #~ msgid "E.g. 119 or 563 for SSL" #~ msgstr "如 SSL 连接用 119 或 563" #~ msgid "WARNINGS" #~ msgstr "警告信息" #~ msgid "Notification classes" #~ msgstr "通知分组" #~ msgid "Enable classes of messages to be reported (none, one or multiple)" #~ msgstr "启用要报告的消息分组 (无、一或多个)" #~ msgid "WARNING: Aborted job \"%s\" because of encrypted RAR file" #~ msgstr "*警告*: 已中止任务 \"%s\",因为发现了加密的 RAR 文件" #~ msgid "" #~ "This key provides identity to indexer. Refer to " #~ "https://www.oznzb.com/profile." #~ msgstr "该 key 向索引器标明身份。参见 https://www.oznzb.com/profile 。" #~ msgid "Automatic Feedback" #~ msgstr "自动反馈" #~ msgid "Site API Key" #~ msgstr "网站 API Key" #~ msgid "" #~ "Enhanced functionality including ratings and extra status information is " #~ "available when connected to OZnzb indexer." #~ msgstr "连接到 OZnzb 索引器可提供增强功能,包括评分与额外的状态信息。" #~ msgid "Enable OZnzb Integration" #~ msgstr "启用 OZnzb 整合" #~ msgid "" #~ "Send automatically calculated validation results for downloads to indexer." #~ msgstr "自动将已下载文件计算完成的验证结果发送到索引器。" #~ msgid "Refer to https://www.oznzb.com/profile" #~ msgstr "参见 https://www.oznzb.com/profile" #~ msgid "OZnzb" #~ msgstr "OZnzb" SABnzbd-2.3.2/po/nsis/da.po0000644000000000000000000000647313217005051013451 0ustar 00000000000000# Danish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2017-04-10 11:28+0000\n" "Last-Translator: Safihre \n" "Language-Team: Danish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Vis udgivelsesbemærkninger" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Støt projektet, donér!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Luk venligst \"SABnzbd.exe\" først" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" "Installationsmappen er ændret (nu i \"Program Files \"). \\nHvis du kører " "SABnzbd som en tjeneste, skal du opdatere tjenesteindstillingerne." #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Dette vil afinstallere SABnzbd fra dit system" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Kør ved opstart" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Skrivebordsikon" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "NZB filtilknytning" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Slet program" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Slet indstillinger" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Dette system kræver, at Microsoft runtime biblioteket VC90 skal installeres " "først. Ønsker du at gøre det nu?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Downloader Microsoft runtime installationsfil..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Download fejl, prøv igen?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "Kan ikke installere uden runtime bibliotek, prøv igen?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Du kan ikke overskrive en eksisterende installation. \\n\\nKlik `OK` for at " "fjerne den tidligere version eller `Annuller` for at annullere denne " "opgradering." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Dine indstillinger og data vil blive bevaret." #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Gå til SABnzbd Wiki" #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> ADVARSEL <<<<\\r\\n\\r\\nVenligst, se først " #~ "produktbemærkningerne eller gå til http://wiki.sabnzbd.org/introducing-0-7-0 " #~ "!" SABnzbd-2.3.2/po/nsis/de.po0000644000000000000000000000701213217005051013443 0ustar 00000000000000# German translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2017-05-22 08:00+0000\n" "Last-Translator: larshuth \n" "Language-Team: German \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Versionshinweise anzeigen" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "Starte SABnzbd" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Bitte unterstützen Sie das Projekt durch eine Spende!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Schliessen Sie bitte zuerst \"SABnzbd.exe\"." #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" "Das Installationsverzeichnis hat sich geändert (nun in \"Program Files\"). \\" "nWenn du SABnzbd als Service ausführst, musst du die Serviceeinstellungen " "anpassen." #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Dies entfernt SABnzbd von Ihrem System" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Beim Systemstart ausführen" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Desktop-Symbol" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "Mit NZB-Dateien verknüpfen" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Programm löschen" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Einstellungen löschen" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Dieses System erfordert die Installation der Laufzeitbibliothek VC90 von " "Microsoft. Möchten Sie die Installation jetzt durchführen?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "" "Installationsprogramm für Microsoft-Laufzeitbibliothek wird " "heruntergeladen..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Download-Fehler. Erneut versuchen?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "" "Installation ohne Laufzeitbibliothek nicht möglich. Erneut versuchen?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Eine vorhandene Installation kann nicht überschrieben werden. \\n\\nWählen " "Sie 'OK', um die vorherige Version zu entfernen oder 'Abbrechen' um die " "Aktualisierung abzubrechen." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Ihre Einstellungen und Daten bleiben erhalten." #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nBitte lesen Sie zuerst die " #~ "Versionshinweise oder gehen Sie zu http://wiki.sabnzbd.org/introducing-0-7-0 " #~ "!" #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Gehen Sie auf die SABnzbd Wiki-Seite" SABnzbd-2.3.2/po/nsis/en.po0000644000000000000000000000002413217004754013462 0ustar 00000000000000# Dummy en.po file SABnzbd-2.3.2/po/nsis/es.po0000644000000000000000000000636413217005051013473 0ustar 00000000000000# Spanish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Victor Herrero \n" "Language-Team: Spanish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Mostrar notas de la versión" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "¡Apoye el proyecto, haga una donación!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Por favor cierre primero \"SABnzbd.exe\"" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Esto desinstalará SABnzbd de su sistema" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Ejecutar al inicio" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Icono del escritorio" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "Asociación de archivos NZB" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Eliminar programa" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Eliminar Ajustes" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Este sistema requiere la ejecución de la biblioteca Microsoft runtime VC90 " "que debe ser instalada. ¿Quieres hacerlo ahora?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Descargando el instalador de Microsoft runtime..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Error en la descarga, ¿probamos de nuevo?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "" "No se puede instalar sin la biblioteca runtime, ¿Lo volvemos a intentar?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "No es posible sobrescribir una instalación existente. \\n\\nPresione `OK' " "para quitar la versión anterior o 'Cancelar' para cancelar la actualización." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Tus ajustes y datos se mantendrán intactos." #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Ir al wiki de SABnzbd" #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> ATENCION <<<<\\r\\n\\r\\nPor favor, compruebe las " #~ "notas de version o visite http://wiki.sabnzbd.org/introducing-0-7-0 !" SABnzbd-2.3.2/po/nsis/fi.po0000644000000000000000000000654313217005051013461 0ustar 00000000000000# Finnish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2017-04-02 07:38+0000\n" "Last-Translator: Paavo Rissanen \n" "Language-Team: Finnish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Näytä julkaisutiedot" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "Käynnistä SABnzbd" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Tue projektia, lahjoita!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Ole hyvä ja sulje \"SABnzbd.exe\" ensin" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" "Asennuskansio on muuttunut (nykyisin \"Program Files\"). \\nJos suoritat " "SABnzbd:ta palveluna, sinun täytyy päivittää palvelun asetukset." #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Tämä poistaa SABnzbd:n tietokoneestasi" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Suorita käynnistyksen yhteydessä" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Työpöydän kuvake" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "NZB tiedostosidos" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Poista sovellus" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Poista asetukset" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Tämä järjestelmä vaatii, että Microsoft runtime kirjasto VC90 täytyy asentaa " "ensin. Haluatko asentaa sen nyt?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Ladataan Microsoft runtime asennusta..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Latausvirhe, yritä uudelleen?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "Ei voida asentaa ilman runtime kirjastoa, yritä uudelleen?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Et voi asentaa tätä vanhan asennuksen päälle. \\n\\nPaina `OK` poistaaksesi " "edellisen version tai paina `Peruuta` peruuttaaksesi tämän päivityksen." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Asetuksiasi ja tietojasi ei poisteta." #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Siirry SABnzbd wikiin" #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> VAROITUS <<<<\\r\\n\\r\\nOle hyvä ja tarkista " #~ "julkaisutiedot tai käy osoitteessa http://wiki.sabnzbd.org/introducing-0-7-0 " #~ "!" SABnzbd-2.3.2/po/nsis/fr.po0000644000000000000000000000677213217005051013476 0ustar 00000000000000# French translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2017-03-21 08:58+0000\n" "Last-Translator: Fred <88com88@gmail.com>\n" "Language-Team: French \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Afficher les notes de version" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "Démarrer SABnzbd" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Soutenez le projet, faites un don !" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Merci de fermer \"SABnzbd.exe\" avant l'installation" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" "Le répertoire d'installation a changé (maintenant dans \"Program Files\"). \\" "nSi vous exécutez SABnzbd en tant que service, vous devez mettre à jour les " "paramètres du service." #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Ceci désinstallera SABnzbd de votre système" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Lancer au démarrage" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Icône sur le Bureau" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "Association des fichiers NZB" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Supprimer le programme" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Supprimer les paramètres" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Ce système nécessite que la bibliothèque d'exécution Microsoft vc90 soit " "installée en premier. Voulez-vous le faire maintenant?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Téléchargement de Microsoft runtime installer..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Erreur de téléchargement, réessayer ?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "Impossible d'installer sans moteur d'exécution, réessayer?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Vous ne pouvez pas remplacer une installation existante. \\n\\nCliquez `OK` " "pour supprimer la version précédente ou `Annuler` pour annuler cette mise à " "niveau." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Vos paramètres et données seront conservés." #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> AVERTISSEMENT <<<<\\r\\n\\r\\nS'il vous plaît, " #~ "vérifiez d'abord les notes de version ou consultez " #~ "http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Aller sur le Wiki de SABnzbd" SABnzbd-2.3.2/po/nsis/he.po0000644000000000000000000000617413217005051013457 0ustar 00000000000000# Hebrew translation for sabnzbd # Copyright (c) 2017 Rosetta Contributors and Canonical Ltd 2017 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2017. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2017-05-06 09:07+0000\n" "Last-Translator: ION IL \n" "Language-Team: Hebrew \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "הראה הערות שחרור" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "התחל את SABnzbd" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "תמוך במיזם, תרום!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "אנא סגור את \"SABnzbd.exe\" תחילה" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" "ספרית ההתקנה השתנתה (עכשיו ב-\"Program Files\"). \\nאם תריץ את SABnzbd בתור " "שירות, אתה צריך לעדכן את הגדרות השירות." #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "זה יסיר את SABnzbd ממערכתך" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "הפעל באתחול" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "צלמית שולחן עבודה" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "שיוך קבצי NZB" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "מחק תכנית" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "מחק הגדרות" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "מערכת זו דורשת את ספרית זמן-אמת VC90 של Microsoft שתהיה מותקנת תחילה. האם " "ברצונך להתקין אותה כעת?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "מוריד מתקין זמן-אמת של Microsoft..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "שגיאת הורדה, לנסות שוב?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "לא ניתן להתקין ללא ספרית זמן-אמת, לנסות שוב?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "אינך יכול לדרוס התקנה קיימת.\\n\\nלחץ על `אישור` כדי להסיר את הגרסה הקודמת " "או על `ביטול` כדי לבטל שדרוג זה." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "ההגדרות והנתונים שלך יישמרו." SABnzbd-2.3.2/po/nsis/nb.po0000644000000000000000000000630113217005051013452 0ustar 00000000000000# Norwegian Bokmal translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: Norwegian Bokmal \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Vis versjonsmerknader" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Støtt prosjektet, donèr!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Vennligst lukk \"SABnzbd.exe\" først" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Dette vil avinstallere SABnzbd fra ditt system" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Kjør ved oppstart" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Skrivebordsikon" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "NZB-filassosiering" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Fjern program" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Slett innstillinger" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Dette sytemet krever at Microsoft runtime library VC90 er installert først. " "Ønsker du å gjøre dette nå?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Laster ned Microsoft runtime installer..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Nedlasting feilet, prøve på nytt?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "Kan ikke installere uten runtime library, prøve på nytt?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Du kan ikke overskrive en eksisterende installasjon. \\n\\nTrykk 'OK' for å " "fjerne tidligere installasjon, eller 'Avbryt' for å avbryte denne " "oppgraderingen." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Dine innstillinger og data vil bli tatt vare på." #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> ADVARSEL <<<<\\r\\n\\r\\nVennligst sjekk " #~ "versjonsmerknadene først, eller gå til http://wiki.sabnzbd.org/introducing-0-" #~ "7-0 !" #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Gå til SABnzbd Wiki" SABnzbd-2.3.2/po/nsis/nl.po0000644000000000000000000000653513217005051013475 0ustar 00000000000000# Dutch translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2017-03-19 09:47+0000\n" "Last-Translator: Safihre \n" "Language-Team: Dutch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Toon opmerkingen bij deze uitgave" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "Start SABnzbd" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Steun het project, doneer!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Sluit \"SABnzbd.exe\" eerst af" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" "De installatie map is veranderd (nu in \"Program Files\").\\nIndien je " "SABnzbd als een service draait, zul je de service instellingen moeten " "aanpassen." #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Dit verwijdert SABnzbd van je systeem" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Starten met Windows" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Bureaubladpictogram" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "NZB-bestanden openen met SABnzbd" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Programma verwijderen" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Verwijder alle instellingen" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Op dit systeem moeten eerst de Microsoft runtime bibliotheek VC90 " "geïnstalleerd worden. Wilt u dat nu doen?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Downloaden van de Microsoft bibliotheek" #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Download mislukt, opnieuw proberen?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "Installeren heeft geen zin zonder de bibliotheek, opnieuw proberen?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "U kunt geen bestaande installatie overschrijven.\\n\\nKlik op `OK` om de " "vorige versie te verwijderen of op `Annuleren` om te stoppen." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Je instellingen en bestanden blijven behouden." #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> WAARSCHUWING <<<<\\\\r\\\\n\\\\r\\\\nLees eerst het " #~ "vrijgave bericht of ga naar http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Ga naar de SABnzbd-Wiki" SABnzbd-2.3.2/po/nsis/pl.po0000644000000000000000000000624013217005051013470 0ustar 00000000000000# Polish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Tomasz 'Zen' Napierala \n" "Language-Team: Polish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Pokaż informacje o wydaniu" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Wspomóż projekt!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Najpierw zamknij SABnzbd.exe" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "To odinstaluje SABnzbd z systemu" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Uruchom wraz z systemem" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Ikona pulpitu" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "powiązanie pliku NZB" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Usuń program" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Skasuj obecne ustawienia" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Ten system wymaga najpierw zainstalowania bibliotek Microsoft VC90. Czy " "chcesz wykonać teraz instalację?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Pobieranie instalatora bibliotek Microsoft..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Problem z pobieraniem, spróbować ponownie?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "Nie można wykonać instalacji bez bibliotek, spróbować ponownie?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Nie można nadpisać istniejącej instalacji. \\n\\n Naciśnij `OK`, aby usunąć " "poprzednia wersję lub `Anuluj` aby anulować aktualizację." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Twoje ustawienia i dane zostaną zachowane." #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> UWAGA <<<<\\r\\n\\r\\nNajpierw przeczytaj informacje " #~ "o wydaniu lub odwiedź http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Idź do wiki SABnzbd" SABnzbd-2.3.2/po/nsis/pt_BR.po0000644000000000000000000000643513217005051014071 0ustar 00000000000000# Brazilian Portuguese translation for sabnzbd # Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2012. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: lrrosa \n" "Language-Team: Brazilian Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Mostrar Notas de Lançamento" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Apoie o projeto. Faça uma doação!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Por favor, feche \"SABnzbd.exe\" primeiro" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Isso irá desinstalar SABnzbd de seu sistema" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Executar na inicialização" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Ícone na Área de Trabalho" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "Associação com Arquivos NZB" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Excluir o Programa" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Apagar Configurações" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Este sistema precisa que a biblioteca runtime Microsoft VC90 seja instalada " "antes. Você quer fazer isso agora?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Baixando o instalador runtime da Microsoft ..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Houve um erro de download. Quer tentar novamente?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "Não é possível instalar sem a biblioteca runtime. Quer repetir?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Você não pode substituir uma instalação existente. \\n\\nClique `OK` para " "remover a versão anterior ou `Cancelar` para cancelar esta atualização." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Suas configurações e os dados serão preservados." #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> ATENÇÃO <<<<\\r\\n\\r\\nPor favor, verifique primeiro " #~ "as notas de lançamento ou vá até http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Vá para a Wiki do SABnzbd" SABnzbd-2.3.2/po/nsis/ro.po0000644000000000000000000000625013217005051013476 0ustar 00000000000000# Romanian translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: nicusor \n" "Language-Team: Romanian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Arată Notele de Publicare" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Susţine proiectul, Donează!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Închideţi mai întâi \"SABnzbd.exe\"" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Acest lucru va dezinstala SABnzbd din sistem" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Executare la pornire" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Icoană Desktop" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "Asociere cu Fişierele NZB" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Şterge Program" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Ştergeţi Setări" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Acest sistem necesită librăria Microsoft VC90 instalată. Dortiți să faceți " "asta acum ?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Descărcare rutină instalare Microsoft..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Eroare descărcare, încerc din nou?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "Nu pot instala fără rutină librărie, încerc din nou?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Nu puteți suprascrie instalarea existentă. \\n\\nClick `OK` pentru a elimina " "versiunea anterioară sau `Anulare` pentru a anula actualizarea." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Setările şi informaţiile vor fi salvate." #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> ATENŢIE <<<<\\r\\n\\r\\nVă rugăm, să verificaţi mai " #~ "întâi notele de publicare sau să vizitaţi " #~ "http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Dute la Wiki SABnzbd" SABnzbd-2.3.2/po/nsis/ru.po0000644000000000000000000000673213217005051013511 0ustar 00000000000000# Russian translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Pavel Maryanov \n" "Language-Team: Russian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Показать заметки о выпуске" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Поддержите проект. Сделайте пожертвование!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Завершите сначала работу процесса SABnzbd.exe" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Приложение SABnzbd будет удалено из вашей системы" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Запускать вместе с системой" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Значок на рабочем столе" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "Ассоциировать с файлами NZB" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Удалить программу" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Удалить параметры" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Для этой системы сначала необходимо установить библиотеку времени выполнения " "Microsoft VC90. Сделать это сейчас?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Загрузка программы установки Microsoft..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Ошибка загрузки. Повторить попытку?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "" "Не удаётся выполнить установку без библиотеки времени выполнения. Повторить " "попытку?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Нельзя перезаписать существующее установленное приложение. \\n\\nЧтобы " "удалить предыдущую версию, нажмите кнопку «ОК». Чтобы отменить обновление, " "нажмите кнопку «Отмена»." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Ваши параметры и данные будут сохранены." SABnzbd-2.3.2/po/nsis/SABnsis.pot0000644000000000000000000000347613217004754014564 0ustar 00000000000000# # SABnzbd Translation Template file NSIS # Copyright 2011-2017 The SABnzbd-Team # team@sabnzbd.org # msgid "" msgstr "" "Project-Id-Version: SABnzbd-2.2.0-develop\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: shypike@sabnzbd.org\n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ASCII\n" "Content-Transfer-Encoding: 7bit\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "" #: NSIS_Installer.nsi msgid "The installation directory has changed (now in \"Program Files\"). \\nIf you run SABnzbd as a service, you need to update the service settings." msgstr "" #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "" #: NSIS_Installer.nsi msgid "This system requires the Microsoft runtime library VC90 to be installed first. Do you want to do that now?" msgstr "" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "" #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "" #: NSIS_Installer.nsi msgid "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove the previous version or `Cancel` to cancel this upgrade." msgstr "" #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "" SABnzbd-2.3.2/po/nsis/sr.po0000644000000000000000000000755213217005051013510 0ustar 00000000000000# Serbian translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # Мирослав Николић , 2011. msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Ozzii \n" "Language-Team: Launchpad Serbian Translators\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" "Language: sr\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Прикажи белешке о издању" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Подржите пројекат, дајте добровољан прилог!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Прво затворите „SABnzbd.exe“" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Ово ће уклонити САБнзбд са вашег система" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Покрени са системом" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Иконица радне површи" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "Придруживање НЗБ датотеке" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Обриши програм" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Обриши подешавања" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Овај систем захтева да буде прво инсталирана Мајкрософтова извршна " "библиотека „VC90“. Да ли желите то да урадите?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Преузимам Мајкрософтов извршни програм за инсталацију..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Грешка у преузимању, да поновим?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "Не могу да инсталирам без извршне библиотеке, да поновим?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Не можете да препишете постојећу инсталацију. \\n\\nПритисните „У реду“ да " "уклоните претходно издање или „Откажи“ да поништите ову надоградњу." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Ваша подешавања и подаци биће сачувани." #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Иди на вики САБнзбд-а" #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> ПАЖЊА <<<<\\r\\n\\r\\nПрво проверите белешке о издању " #~ "или идите на „http://wiki.sabnzbd.org/introducing-0-7-0“ !" SABnzbd-2.3.2/po/nsis/sv.po0000644000000000000000000000632213217005051013506 0ustar 00000000000000# Swedish translation for sabnzbd # Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2011. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2013-05-05 14:50+0000\n" "Last-Translator: Andreas Lindberg \n" "Language-Team: Swedish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "Visa releasenoteringar" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "Donera och stöd detta projekt!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "Var vänlig stäng \"SABnzbd.exe\" först" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "" #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "Detta kommer att avinstallera SABnzbd från systemet" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "Kör vid uppstart" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "Skrivbordsikon" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "NZB Filassosication" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "Radera programmet" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "Radera inställningar" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "" "Detta system kräver att Microsofts runtimebibliotek VC90 är installerat. " "Vill du göra detta nu?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "Laddar ned Microsofts runtimeinstaller..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "Misslyckat nedladdningsförsök, försök igen?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "Kan inte installera utan runtimebibliotek, försök igen?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "" "Kan inte skriva över en existerande installation. \\n\\nKlicka 'OK' för att " "avinstallera tidigare version eller 'Avbryt' för att avbryta denna " "uppgradering." #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "Dina inställningar och ditt data kommer att bevaras." #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "Gå till SABnzbd Wiki" #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> VARNING <<<<\\r\\n\\r\\nVänligen läs först " #~ "releasenoteringarna eller gå till http://wiki.sabnzbd.org/introducing-0-7-0 !" SABnzbd-2.3.2/po/nsis/zh_CN.po0000644000000000000000000000623513217005051014062 0ustar 00000000000000# Chinese (Simplified) translation for sabnzbd # Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 # This file is distributed under the same license as the sabnzbd package. # FIRST AUTHOR , 2012. # msgid "" msgstr "" "Project-Id-Version: sabnzbd\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2017-06-22 20:42+0000\n" "PO-Revision-Date: 2017-05-28 17:17+0000\n" "Last-Translator: ninjai \n" "Language-Team: Chinese (Simplified) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n" "X-Generator: Launchpad (build 18416)\n" #: NSIS_Installer.nsi msgid "Show Release Notes" msgstr "显示版本说明" #: NSIS_Installer.nsi msgid "Start SABnzbd" msgstr "启动 SABnzbd" #: NSIS_Installer.nsi msgid "Support the project, Donate!" msgstr "支持该项目,捐助!" #: NSIS_Installer.nsi msgid "Please close \"SABnzbd.exe\" first" msgstr "请先关闭 \"SABnzbd.exe\"" #: NSIS_Installer.nsi msgid "" "The installation directory has changed (now in \"Program Files\"). \\nIf you " "run SABnzbd as a service, you need to update the service settings." msgstr "安装目录已更改(现在位于 \"Program Files\" 目录)。\\n如果以服务模式运行,你需要更新相应服务的设置。" #: NSIS_Installer.nsi msgid "This will uninstall SABnzbd from your system" msgstr "这将从您的系统中卸载 SABnzbd" #: NSIS_Installer.nsi msgid "Run at startup" msgstr "启动时运行" #: NSIS_Installer.nsi msgid "Desktop Icon" msgstr "桌面图标" #: NSIS_Installer.nsi msgid "NZB File association" msgstr "NZB 文件关联" #: NSIS_Installer.nsi msgid "Delete Program" msgstr "删除程序" #: NSIS_Installer.nsi msgid "Delete Settings" msgstr "删除设置" #: NSIS_Installer.nsi msgid "" "This system requires the Microsoft runtime library VC90 to be installed " "first. Do you want to do that now?" msgstr "该系统需要先安装 Microsoft 运行时库 VC90。是否希望立即安装?" #: NSIS_Installer.nsi msgid "Downloading Microsoft runtime installer..." msgstr "正在下载 Microsoft 运行时安装程序..." #: NSIS_Installer.nsi msgid "Download error, retry?" msgstr "下载出错,重试?" #: NSIS_Installer.nsi msgid "Cannot install without runtime library, retry?" msgstr "没有运行时库无法安装,重试?" #: NSIS_Installer.nsi msgid "" "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove " "the previous version or `Cancel` to cancel this upgrade." msgstr "不可以覆盖安装。\\n\\n点击“确定”可移除旧版,或点击“取消”取消升级。" #: NSIS_Installer.nsi msgid "Your settings and data will be preserved." msgstr "您的设置及数据将会保留。" #~ msgid "" #~ " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the " #~ "release notes or go to http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgstr "" #~ " >>>> *警告* <<<<\\r\\n\\r\\n请首先查看版本说明或访问 " #~ "http://wiki.sabnzbd.org/introducing-0-7-0 !" #~ msgid "Go to the SABnzbd Wiki" #~ msgstr "访问 SABnzbd Wiki" SABnzbd-2.3.2/sabnzbd/api.py0000644000000000000000000021337613217005257013713 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.api - api """ import os import logging import re import datetime import time import json import cherrypy import locale from threading import Thread try: locale.setlocale(locale.LC_ALL, "") except: # Work-around for Python-ports with bad "locale" support pass try: import win32api import win32file except ImportError: pass import sabnzbd from sabnzbd.constants import VALID_ARCHIVES, Status, \ TOP_PRIORITY, REPAIR_PRIORITY, HIGH_PRIORITY, NORMAL_PRIORITY, LOW_PRIORITY, \ KIBI, MEBI, GIGI, JOB_ADMIN import sabnzbd.config as config import sabnzbd.cfg as cfg from sabnzbd.downloader import Downloader from sabnzbd.nzbqueue import NzbQueue import sabnzbd.scheduler as scheduler from sabnzbd.skintext import SKIN_TEXT from sabnzbd.utils.json import JsonWriter from sabnzbd.utils.rsslib import RSS, Item from sabnzbd.utils.pathbrowser import folders_at_path from sabnzbd.utils.getperformance import getcpu from sabnzbd.misc import loadavg, to_units, diskspace, get_ext, \ get_filename, int_conv, globber, globber_full, time_format, remove_all, \ starts_with_path, cat_convert, clip_path, create_https_certificates, calc_age from sabnzbd.encoding import xml_name, unicoder, special_fixer, platform_encode, html_escape from sabnzbd.postproc import PostProcessor from sabnzbd.articlecache import ArticleCache from sabnzbd.utils.servertests import test_nntp_server_dict from sabnzbd.bpsmeter import BPSMeter from sabnzbd.rating import Rating from sabnzbd.getipaddress import localipv4, publicipv4, ipv6 from sabnzbd.newsunpack import userxbit from sabnzbd.database import build_history_info, unpack_history_info, HistoryDB import sabnzbd.notifier import sabnzbd.rss import sabnzbd.emailer import sabnzbd.getipaddress as getipaddress ############################################################################## # API error messages ############################################################################## _MSG_NO_VALUE = 'expect one parameter' _MSG_NO_VALUE2 = 'expect two parameters' _MSG_INT_VALUE = 'expect integer value' _MSG_NO_ITEM = 'item does not exist' _MSG_NOT_IMPLEMENTED = 'not implemented' _MSG_NO_FILE = 'no file given' _MSG_NO_PATH = 'file does not exist' _MSG_OUTPUT_FORMAT = 'Format not supported' _MSG_NO_SUCH_CONFIG = 'Config item does not exist' _MSG_BAD_SERVER_PARMS = 'Incorrect server settings' # For Windows: determine executable extensions if os.name == 'nt': PATHEXT = os.environ.get('PATHEXT', '').lower().split(';') else: PATHEXT = [] # Flag for using the fast json encoder, unless it fails FAST_JSON = True def api_handler(kwargs): """ API Dispatcher """ mode = kwargs.get('mode', '') output = kwargs.get('output') name = kwargs.get('name', '') callback = kwargs.get('callback', '') if isinstance(mode, list): mode = mode[0] if isinstance(output, list): output = output[0] response = _api_table.get(mode, (_api_undefined, 2))[0](name, output, kwargs) if output == 'json' and callback: response = '%s(%s)' % (callback, response) return response def _api_get_config(name, output, kwargs): """ API: accepts output, keyword, section """ _, data = config.get_dconfig(kwargs.get('section'), kwargs.get('keyword')) return report(output, keyword='config', data=data) def _api_set_config(name, output, kwargs): """ API: accepts output, keyword, section """ if kwargs.get('section') == 'servers': kwargs['keyword'] = handle_server_api(output, kwargs) elif kwargs.get('section') == 'rss': kwargs['keyword'] = handle_rss_api(output, kwargs) elif kwargs.get('section') == 'categories': kwargs['keyword'] = handle_cat_api(output, kwargs) else: res = config.set_config(kwargs) if not res: return report(output, _MSG_NO_SUCH_CONFIG) config.save_config() res, data = config.get_dconfig(kwargs.get('section'), kwargs.get('keyword')) return report(output, keyword='config', data=data) def _api_set_config_default(name, output, kwargs): """ API: Reset requested config variables back to defaults. Currently only for misc-section """ keywords = kwargs.get('keyword', []) if not isinstance(keywords, list): keywords = [keywords] for keyword in keywords: item = config.get_config('misc', keyword) if item: item.set(item.default()) config.save_config() return report(output) def _api_del_config(name, output, kwargs): """ API: accepts output, keyword, section """ if del_from_section(kwargs): return report(output) else: return report(output, _MSG_NOT_IMPLEMENTED) def _api_qstatus(name, output, kwargs): """ API: accepts output """ info, pnfo_list, bytespersec = build_queue() return report(output, data=remove_callable(info)) def _api_queue(name, output, kwargs): """ API: Dispatcher for mode=queue """ value = kwargs.get('value', '') return _api_queue_table.get(name, (_api_queue_default, 2))[0](output, value, kwargs) def _api_queue_delete(output, value, kwargs): """ API: accepts output, value """ if value.lower() == 'all': removed = NzbQueue.do.remove_all(kwargs.get('search')) return report(output, keyword='', data={'status': bool(removed), 'nzo_ids': removed}) elif value: items = value.split(',') del_files = int_conv(kwargs.get('del_files')) removed = NzbQueue.do.remove_multiple(items, del_files) return report(output, keyword='', data={'status': bool(removed), 'nzo_ids': removed}) else: return report(output, _MSG_NO_VALUE) def _api_queue_delete_nzf(output, value, kwargs): """ API: accepts value(=nzo_id), value2(=nzf_id) """ value2 = kwargs.get('value2') if value and value2: removed = NzbQueue.do.remove_nzf(value, value2, force_delete=True) return report(output, keyword='', data={'status': bool(removed), 'nzf_ids': removed}) else: return report(output, _MSG_NO_VALUE2) def _api_queue_rename(output, value, kwargs): """ API: accepts output, value(=old name), value2(=new name), value3(=password) """ value2 = kwargs.get('value2') value3 = kwargs.get('value3') if value and value2: ret = NzbQueue.do.change_name(value, special_fixer(value2), special_fixer(value3)) return report(output, keyword='', data={'status': ret}) else: return report(output, _MSG_NO_VALUE2) def _api_queue_change_complete_action(output, value, kwargs): """ API: accepts output, value(=action) """ sabnzbd.change_queue_complete_action(value) return report(output) def _api_queue_purge(output, value, kwargs): """ API: accepts output """ removed = NzbQueue.do.remove_all(kwargs.get('search')) return report(output, keyword='', data={'status': bool(removed), 'nzo_ids': removed}) def _api_queue_pause(output, value, kwargs): """ API: accepts output, value(=list of nzo_id) """ if value: items = value.split(',') handled = NzbQueue.do.pause_multiple_nzo(items) return report(output, keyword='', data={'status': bool(handled), 'nzo_ids': handled}) def _api_queue_resume(output, value, kwargs): """ API: accepts output, value(=list of nzo_id) """ if value: items = value.split(',') handled = NzbQueue.do.resume_multiple_nzo(items) return report(output, keyword='', data={'status': bool(handled), 'nzo_ids': handled}) def _api_queue_priority(output, value, kwargs): """ API: accepts output, value(=nzo_id), value2(=priority) """ value2 = kwargs.get('value2') if value and value2: try: try: priority = int(value2) except: return report(output, _MSG_INT_VALUE) pos = NzbQueue.do.set_priority(value, priority) # Returns the position in the queue, -1 is incorrect job-id return report(output, keyword='position', data=pos) except: return report(output, _MSG_NO_VALUE2) else: return report(output, _MSG_NO_VALUE2) def _api_queue_sort(output, value, kwargs): """ API: accepts output, sort, dir """ sort = kwargs.get('sort') direction = kwargs.get('dir', '') if sort: NzbQueue.do.sort_queue(sort, direction) return report(output) else: return report(output, _MSG_NO_VALUE2) def _api_queue_default(output, value, kwargs): """ API: accepts output, sort, dir, start, limit """ start = int_conv(kwargs.get('start')) limit = int_conv(kwargs.get('limit')) search = kwargs.get('search') if output in ('xml', 'json'): info, pnfo_list, bytespersec = build_queue(start=start, limit=limit, output=output, search=search) return report(output, keyword='queue', data=remove_callable(info)) elif output == 'rss': return rss_qstatus() else: return report(output, _MSG_NOT_IMPLEMENTED) def _api_queue_rating(output, value, kwargs): """ API: accepts output, value(=nzo_id), type, setting, detail """ vote_map = {'up': Rating.VOTE_UP, 'down': Rating.VOTE_DOWN} flag_map = {'spam': Rating.FLAG_SPAM, 'encrypted': Rating.FLAG_ENCRYPTED, 'expired': Rating.FLAG_EXPIRED, 'other': Rating.FLAG_OTHER, 'comment': Rating.FLAG_COMMENT} content_type = kwargs.get('type') setting = kwargs.get('setting') if value: try: video = audio = vote = flag = None if content_type == 'video' and setting != "-": video = setting if content_type == 'audio' and setting != "-": audio = setting if content_type == 'vote': vote = vote_map[setting] if content_type == 'flag': flag = flag_map[setting] if cfg.rating_enable(): Rating.do.update_user_rating(value, video, audio, vote, flag, kwargs.get('detail')) return report(output) except: return report(output, _MSG_BAD_SERVER_PARMS) else: return report(output, _MSG_NO_VALUE) def _api_options(name, output, kwargs): """ API: accepts output """ return options_list(output) def _api_translate(name, output, kwargs): """ API: accepts output, value(=acronym) """ return report(output, keyword='value', data=Tx(kwargs.get('value', ''))) def _api_addfile(name, output, kwargs): """ API: accepts name, output, pp, script, cat, priority, nzbname """ # When uploading via flash it will send the nzb in a kw arg called Filedata if name is None or isinstance(name, basestring): name = kwargs.get('Filedata') # Normal upload will send the nzb in a kw arg called nzbfile if name is None or isinstance(name, basestring): name = kwargs.get('nzbfile') if hasattr(name, 'getvalue'): # Side effect of next line is that attribute .value is created # which is needed to make add_nzbfile() work size = name.length elif hasattr(name, 'file') and hasattr(name, 'filename') and name.filename: # CherryPy 3.2.2 object if hasattr(name.file, 'file'): name.value = name.file.file.read() else: name.value = name.file.read() size = len(name.value) elif hasattr(name, 'value'): size = len(name.value) else: size = 0 if name is not None and size and name.filename: cat = kwargs.get('cat') xcat = kwargs.get('xcat') if not cat and xcat: # Indexer category, so do mapping cat = cat_convert(xcat) res = sabnzbd.add_nzbfile(name, kwargs.get('pp'), kwargs.get('script'), cat, kwargs.get('priority'), kwargs.get('nzbname')) return report(output, keyword='', data={'status': res[0] == 0, 'nzo_ids': res[1]}, compat=True) else: return report(output, _MSG_NO_VALUE) def _api_retry(name, output, kwargs): """ API: accepts name, output, value(=nzo_id), nzbfile(=optional NZB), password (optional) """ value = kwargs.get('value') # When uploading via flash it will send the nzb in a kw arg called Filedata if name is None or isinstance(name, basestring): name = kwargs.get('Filedata') # Normal upload will send the nzb in a kw arg called nzbfile if name is None or isinstance(name, basestring): name = kwargs.get('nzbfile') password = kwargs.get('password') password = password[0] if isinstance(password, list) else password nzo_id = retry_job(value, name, password) if nzo_id: if isinstance(nzo_id, list): nzo_id = nzo_id[0] return report(output, keyword='', data={'status': True, 'nzo_id': nzo_id}) else: return report(output, _MSG_NO_ITEM) def _api_cancel_pp(name, output, kwargs): """ API: accepts name, output, value(=nzo_id) """ nzo_id = kwargs.get('value') if PostProcessor.do.cancel_pp(nzo_id): return report(output, keyword='', data={'status': True, 'nzo_id': nzo_id}) else: return report(output, _MSG_NO_ITEM) def _api_addlocalfile(name, output, kwargs): """ API: accepts name, output, pp, script, cat, priority, nzbname """ if name and isinstance(name, list): name = name[0] if name: if os.path.exists(name): fn = get_filename(name) if fn: pp = kwargs.get('pp') script = kwargs.get('script') cat = kwargs.get('cat') xcat = kwargs.get('xcat') if not cat and xcat: # Indexer category, so do mapping cat = cat_convert(xcat) priority = kwargs.get('priority') nzbname = kwargs.get('nzbname') if get_ext(name) in VALID_ARCHIVES: res = sabnzbd.dirscanner.ProcessArchiveFile( fn, name, pp=pp, script=script, cat=cat, priority=priority, keep=True, nzbname=nzbname) elif get_ext(name) in ('.nzb', '.gz', '.bz2'): res = sabnzbd.dirscanner.ProcessSingleFile( fn, name, pp=pp, script=script, cat=cat, priority=priority, keep=True, nzbname=nzbname) else: logging.info('API-call addlocalfile: "%s" not a proper file name', name) return report(output, _MSG_NO_FILE) else: logging.info('API-call addlocalfile: file "%s" not found', name) return report(output, _MSG_NO_PATH) return report(output, keyword='', data={'status': res[0] == 0, 'nzo_ids': res[1]}, compat=True) else: logging.info('API-call addlocalfile: no file name given') return report(output, _MSG_NO_VALUE) def _api_switch(name, output, kwargs): """ API: accepts output, value(=first id), value2(=second id) """ value = kwargs.get('value') value2 = kwargs.get('value2') if value and value2: pos, prio = NzbQueue.do.switch(value, value2) # Returns the new position and new priority (if different) if output not in ('xml', 'json'): return report(output, data=(pos, prio)) else: return report(output, keyword='result', data={'position': pos, 'priority': prio}) else: return report(output, _MSG_NO_VALUE2) def _api_change_cat(name, output, kwargs): """ API: accepts output, value(=nzo_id), value2(=category) """ value = kwargs.get('value') value2 = kwargs.get('value2') if value and value2: nzo_id = value cat = value2 if cat == 'None': cat = None result = NzbQueue.do.change_cat(nzo_id, cat) return report(output, keyword='status', data=bool(result > 0)) else: return report(output, _MSG_NO_VALUE) def _api_change_script(name, output, kwargs): """ API: accepts output, value(=nzo_id), value2(=script) """ value = kwargs.get('value') value2 = kwargs.get('value2') if value and value2: nzo_id = value script = value2 if script.lower() == 'none': script = None result = NzbQueue.do.change_script(nzo_id, script) return report(output, keyword='status', data=bool(result > 0)) else: return report(output, _MSG_NO_VALUE) def _api_change_opts(name, output, kwargs): """ API: accepts output, value(=nzo_id), value2(=pp) """ value = kwargs.get('value') value2 = kwargs.get('value2') if value and value2 and value2.isdigit(): result = NzbQueue.do.change_opts(value, int(value2)) return report(output, keyword='status', data=bool(result > 0)) def _api_fullstatus(name, output, kwargs): """ API: full history status""" status = build_status(skip_dashboard=kwargs.get('skip_dashboard', 1), output=output) return report(output, keyword='status', data=remove_callable(status)) def _api_history(name, output, kwargs): """ API: accepts output, value(=nzo_id), start, limit, search """ value = kwargs.get('value', '') start = int_conv(kwargs.get('start')) limit = int_conv(kwargs.get('limit')) last_history_update = int_conv(kwargs.get('last_history_update', 0)) search = kwargs.get('search') failed_only = kwargs.get('failed_only') categories = kwargs.get('category') # Do we need to send anything? if last_history_update == sabnzbd.LAST_HISTORY_UPDATE: return report(output, keyword='history', data=False) if categories and not isinstance(categories, list): categories = [categories] if not limit: limit = cfg.history_limit() if name == 'delete': special = value.lower() del_files = bool(int_conv(kwargs.get('del_files'))) if special in ('all', 'failed', 'completed'): history_db = sabnzbd.connect_db() if special in ('all', 'failed'): if del_files: del_job_files(history_db.get_failed_paths(search)) history_db.remove_failed(search) if special in ('all', 'completed'): history_db.remove_completed(search) sabnzbd.history_updated() return report(output) elif value: jobs = value.split(',') for job in jobs: del_hist_job(job, del_files) sabnzbd.history_updated() return report(output) else: return report(output, _MSG_NO_VALUE) elif not name: history = {} grand, month, week, day = BPSMeter.do.get_sums() history['total_size'], history['month_size'], history['week_size'], history['day_size'] = \ to_units(grand), to_units(month), to_units(week), to_units(day) history['slots'], fetched_items, history['noofslots'] = build_history(start=start, limit=limit, verbose=True, search=search, failed_only=failed_only, categories=categories, output=output) history['last_history_update'] = sabnzbd.LAST_HISTORY_UPDATE history['version'] = sabnzbd.__version__ return report(output, keyword='history', data=remove_callable(history)) else: return report(output, _MSG_NOT_IMPLEMENTED) def _api_get_files(name, output, kwargs): """ API: accepts output, value(=nzo_id) """ value = kwargs.get('value') if value: return report(output, keyword='files', data=build_file_list(value)) else: return report(output, _MSG_NO_VALUE) def _api_addurl(names, output, kwargs): """ API: accepts name, output, pp, script, cat, priority, nzbname """ pp = kwargs.get('pp') script = kwargs.get('script') cat = kwargs.get('cat') priority = kwargs.get('priority') nzbnames = kwargs.get('nzbname') if not isinstance(names, list): names = [names] if not isinstance(nzbnames, list): nzbnames = [nzbnames] nzo_ids = [] for n in xrange(len(names)): name = names[n] if n < len(nzbnames): nzbname = nzbnames[n] else: nzbname = '' if name: name = name.strip() if name: nzo_ids.append(sabnzbd.add_url(name, pp, script, cat, priority, nzbname)) if len(names) > 0: return report(output, keyword='', data={'status': True, 'nzo_ids': nzo_ids}, compat=True) else: logging.info('API-call addurl: no files retrieved from %s', names) return report(output, _MSG_NO_VALUE) def _api_pause(name, output, kwargs): """ API: accepts output """ scheduler.plan_resume(0) Downloader.do.pause() return report(output) def _api_resume(name, output, kwargs): """ API: accepts output """ scheduler.plan_resume(0) sabnzbd.unpause_all() return report(output) def _api_shutdown(name, output, kwargs): """ API: accepts output """ logging.info('Shutdown requested by API') sabnzbd.halt() cherrypy.engine.exit() sabnzbd.SABSTOP = True return report(output) def _api_warnings(name, output, kwargs): """ API: accepts name, output """ if name == 'clear': return report(output, keyword="warnings", data=sabnzbd.GUIHANDLER.clear()) elif name == 'show': return report(output, keyword="warnings", data=sabnzbd.GUIHANDLER.content()) elif name: return report(output, _MSG_NOT_IMPLEMENTED) return report(output, keyword="warnings", data=sabnzbd.GUIHANDLER.content()) def _api_get_cats(name, output, kwargs): """ API: accepts output """ return report(output, keyword="categories", data=list_cats(False)) def _api_get_scripts(name, output, kwargs): """ API: accepts output """ data = [unicoder(val) for val in list_scripts()] return report(output, keyword="scripts", data=data) def _api_version(name, output, kwargs): """ API: accepts output """ return report(output, keyword='version', data=sabnzbd.__version__) def _api_auth(name, output, kwargs): """ API: accepts output """ auth = 'None' if not cfg.disable_key(): auth = 'badkey' key = kwargs.get('key', '') if not key: auth = 'apikey' else: if key == cfg.nzb_key(): auth = 'nzbkey' if key == cfg.api_key(): auth = 'apikey' elif cfg.username() and cfg.password(): auth = 'login' return report(output, keyword='auth', data=auth) def _api_restart(name, output, kwargs): """ API: accepts output """ logging.info('Restart requested by API') # Do the shutdown async to still send goodbye to browser Thread(target=sabnzbd.trigger_restart, kwargs={'timeout': 1}).start() return report(output) def _api_restart_repair(name, output, kwargs): """ API: accepts output """ logging.info('Queue repair requested by API') sabnzbd.request_repair() sabnzbd.trigger_restart() return report(output) def _api_disconnect(name, output, kwargs): """ API: accepts output """ Downloader.do.disconnect() return report(output) def _api_osx_icon(name, output, kwargs): """ API: accepts output, value """ value = kwargs.get('value', '1').strip() cfg.osx_menu.set(value != '0') return report(output) def _api_rescan(name, output, kwargs): """ API: accepts output """ NzbQueue.do.scan_jobs(all=False, action=True) return report(output) def _api_eval_sort(name, output, kwargs): """ API: evaluate sorting expression """ name = kwargs.get('name', '') value = kwargs.get('value', '') title = kwargs.get('title') multipart = kwargs.get('movieextra', '') path = sabnzbd.sorting.eval_sort(value, title, name, multipart) if path is None: return report(output, _MSG_NOT_IMPLEMENTED) else: return report(output, keyword='result', data=path) def _api_watched_now(name, output, kwargs): """ API: accepts output """ sabnzbd.dirscanner.dirscan() return report(output) def _api_resume_pp(name, output, kwargs): """ API: accepts output """ PostProcessor.do.paused = False return report(output) def _api_pause_pp(name, output, kwargs): """ API: accepts output """ PostProcessor.do.paused = True return report(output) def _api_rss_now(name, output, kwargs): """ API: accepts output """ # Run RSS scan async, because it can take a long time scheduler.force_rss() return report(output) def _api_retry_all(name, output, kwargs): """ API: Retry all failed items in History """ return report(output, keyword='status', data=retry_all_jobs()) def _api_reset_quota(name, output, kwargs): """ Reset quota left """ BPSMeter.do.reset_quota(force=True) def _api_test_email(name, output, kwargs): """ API: send a test email, return result """ logging.info("Sending test email") pack = {} pack['download'] = ['action 1', 'action 2'] pack['unpack'] = ['action 1', 'action 2'] res = sabnzbd.emailer.endjob(u'I had a d\xe8ja vu', 'unknown', True, os.path.normpath(os.path.join(cfg.complete_dir.get_path(), u'/unknown/I had a d\xe8ja vu')), 123 * MEBI, None, pack, 'my_script', u'Line 1\nLine 2\nLine 3\nd\xe8ja vu\n', 0, test=kwargs) if res == 'Email succeeded': res = None return report(output, error=res) def _api_test_windows(name, output, kwargs): """ API: send a test to Windows, return result """ logging.info("Sending test notification") res = sabnzbd.notifier.send_windows('SABnzbd', T('Test Notification'), 'other') return report(output, error=res) def _api_test_notif(name, output, kwargs): """ API: send a test to Notification Center, return result """ logging.info("Sending test notification") res = sabnzbd.notifier.send_notification_center('SABnzbd', T('Test Notification'), 'other') return report(output, error=res) def _api_test_growl(name, output, kwargs): """ API: send a test Growl notification, return result """ logging.info("Sending Growl notification") res = sabnzbd.notifier.send_growl('SABnzbd', T('Test Notification'), 'other', test=kwargs) return report(output, error=res) def _api_test_osd(name, output, kwargs): """ API: send a test OSD notification, return result """ logging.info("Sending OSD notification") res = sabnzbd.notifier.send_notify_osd('SABnzbd', T('Test Notification')) return report(output, error=res) def _api_test_prowl(name, output, kwargs): """ API: send a test Prowl notification, return result """ logging.info("Sending Prowl notification") res = sabnzbd.notifier.send_prowl('SABnzbd', T('Test Notification'), 'other', force=True, test=kwargs) return report(output, error=res) def _api_test_pushover(name, output, kwargs): """ API: send a test Pushover notification, return result """ logging.info("Sending Pushover notification") res = sabnzbd.notifier.send_pushover('SABnzbd', T('Test Notification'), 'other', force=True, test=kwargs) return report(output, error=res) def _api_test_pushbullet(name, output, kwargs): """ API: send a test Pushbullet notification, return result """ logging.info("Sending Pushbullet notification") res = sabnzbd.notifier.send_pushbullet('SABnzbd', T('Test Notification'), 'other', force=True, test=kwargs) return report(output, error=res) def _api_test_nscript(name, output, kwargs): """ API: execute a test notification script, return result """ logging.info("Executing notification script") res = sabnzbd.notifier.send_nscript('SABnzbd', T('Test Notification'), 'other', force=True, test=kwargs) return report(output, error=res) def _api_undefined(name, output, kwargs): """ API: accepts output """ return report(output, _MSG_NOT_IMPLEMENTED) def _api_browse(name, output, kwargs): """ Return tree of local path """ compact = kwargs.get('compact') if compact and compact == '1': paths = [] name = platform_encode(kwargs.get('term', '')) paths = [entry['path'] for entry in folders_at_path(os.path.dirname(name)) if 'path' in entry] return report(output, keyword='', data=paths) else: name = platform_encode(name) show_hidden = kwargs.get('show_hidden_folders') paths = folders_at_path(name, True, show_hidden) return report(output, keyword='paths', data=paths) def _api_config(name, output, kwargs): """ API: Dispatcher for "config" """ return _api_config_table.get(name, (_api_config_undefined, 2))[0](output, kwargs) def _api_config_speedlimit(output, kwargs): """ API: accepts output, value(=speed) """ value = kwargs.get('value') if not value: value = '0' Downloader.do.limit_speed(value) return report(output) def _api_config_get_speedlimit(output, kwargs): """ API: accepts output """ return report(output, keyword='speedlimit', data=Downloader.do.get_limit()) def _api_config_set_colorscheme(output, kwargs): """ API: accepts output""" value = kwargs.get('value') if value: cfg.web_color.set(value) return report(output) else: return report(output, _MSG_NO_VALUE) def _api_config_set_pause(output, kwargs): """ API: accepts output, value(=pause interval) """ value = kwargs.get('value') scheduler.plan_resume(int_conv(value)) return report(output) def _api_config_set_apikey(output, kwargs): """ API: accepts output """ cfg.api_key.set(config.create_api_key()) config.save_config() return report(output, keyword='apikey', data=cfg.api_key()) def _api_config_set_nzbkey(output, kwargs): """ API: accepts output """ cfg.nzb_key.set(config.create_api_key()) config.save_config() return report(output, keyword='nzbkey', data=cfg.nzb_key()) def _api_config_regenerate_certs(output, kwargs): # Make sure we only over-write default locations result = False if sabnzbd.cfg.https_cert() is sabnzbd.cfg.https_cert.default() and sabnzbd.cfg.https_key() is sabnzbd.cfg.https_key.default(): https_cert = sabnzbd.cfg.https_cert.get_path() https_key = sabnzbd.cfg.https_key.get_path() result = create_https_certificates(https_cert, https_key) sabnzbd.RESTART_REQ = True return report(output, data=result) def _api_config_test_server(output, kwargs): """ API: accepts output, server-params """ result, msg = test_nntp_server_dict(kwargs) response = {'result': result, 'message': msg} if output: return report(output, data=response) else: return msg def _api_config_undefined(output, kwargs): """ API: accepts output """ return report(output, _MSG_NOT_IMPLEMENTED) def _api_server_stats(name, output, kwargs): """ API: accepts output """ sum_t, sum_m, sum_w, sum_d = BPSMeter.do.get_sums() stats = {'total': sum_t, 'month': sum_m, 'week': sum_w, 'day': sum_d} stats['servers'] = {} for svr in config.get_servers(): t, m, w, d, daily = BPSMeter.do.amounts(svr) stats['servers'][svr] = {'total': t or 0, 'month': m or 0, 'week': w or 0, 'day': d or 0, 'daily': daily or {} } return report(output, keyword='', data=stats) ############################################################################## _api_table = { 'server_stats': (_api_server_stats, 2), 'get_config': (_api_get_config, 3), 'set_config': (_api_set_config, 3), 'set_config_default': (_api_set_config_default, 3), 'del_config': (_api_del_config, 3), 'qstatus': (_api_qstatus, 2), 'queue': (_api_queue, 2), 'options': (_api_options, 2), 'translate': (_api_translate, 2), 'addfile': (_api_addfile, 1), 'retry': (_api_retry, 2), 'cancel_pp': (_api_cancel_pp, 2), 'addlocalfile': (_api_addlocalfile, 1), 'switch': (_api_switch, 2), 'change_cat': (_api_change_cat, 2), 'change_script': (_api_change_script, 2), 'change_opts': (_api_change_opts, 2), 'fullstatus': (_api_fullstatus, 2), 'history': (_api_history, 2), 'get_files': (_api_get_files, 2), 'addurl': (_api_addurl, 1), 'addid': (_api_addurl, 1), 'pause': (_api_pause, 2), 'resume': (_api_resume, 2), 'shutdown': (_api_shutdown, 3), 'warnings': (_api_warnings, 2), 'config': (_api_config, 2), 'get_cats': (_api_get_cats, 2), 'get_scripts': (_api_get_scripts, 2), 'version': (_api_version, 1), 'auth': (_api_auth, 1), 'restart': (_api_restart, 3), 'restart_repair': (_api_restart_repair, 2), 'disconnect': (_api_disconnect, 2), 'osx_icon': (_api_osx_icon, 3), 'rescan': (_api_rescan, 2), 'eval_sort': (_api_eval_sort, 2), 'watched_now': (_api_watched_now, 2), 'resume_pp': (_api_resume_pp, 2), 'pause_pp': (_api_pause_pp, 2), 'rss_now': (_api_rss_now, 2), 'browse': (_api_browse, 2), 'retry_all': (_api_retry_all, 2), 'reset_quota': (_api_reset_quota, 2), 'test_email': (_api_test_email, 2), 'test_windows': (_api_test_windows, 2), 'test_notif': (_api_test_notif, 2), 'test_growl': (_api_test_growl, 2), 'test_osd': (_api_test_osd, 2), 'test_pushover': (_api_test_pushover, 2), 'test_pushbullet': (_api_test_pushbullet, 2), 'test_prowl': (_api_test_prowl, 2), 'test_nscript': (_api_test_nscript, 2), } _api_queue_table = { 'delete': (_api_queue_delete, 2), 'delete_nzf': (_api_queue_delete_nzf, 2), 'rename': (_api_queue_rename, 2), 'change_complete_action': (_api_queue_change_complete_action, 2), 'purge': (_api_queue_purge, 2), 'pause': (_api_queue_pause, 2), 'resume': (_api_queue_resume, 2), 'priority': (_api_queue_priority, 2), 'sort': (_api_queue_sort, 2), 'rating': (_api_queue_rating, 2) } _api_config_table = { 'speedlimit': (_api_config_speedlimit, 2), 'set_speedlimit': (_api_config_speedlimit, 2), 'get_speedlimit': (_api_config_get_speedlimit, 2), 'set_colorscheme': (_api_config_set_colorscheme, 2), 'set_pause': (_api_config_set_pause, 2), 'set_apikey': (_api_config_set_apikey, 3), 'set_nzbkey': (_api_config_set_nzbkey, 3), 'regenerate_certs': (_api_config_regenerate_certs, 3), 'test_server': (_api_config_test_server, 2) } def api_level(cmd, name): """ Return access level required for this API call """ if cmd in _api_table: return _api_table[cmd][1] if name == 'queue' and cmd in _api_queue_table: return _api_queue_table[cmd][1] if name == 'config' and cmd in _api_config_table: return _api_config_table[cmd][1] return 4 def report(output, error=None, keyword='value', data=None, callback=None, compat=False): """ Report message in json, xml or plain text If error is set, only an status/error report is made. If no error and no data, only a status report is made. Else, a data report is made (optional 'keyword' for outer XML section). 'compat' is a special case for compatibility for ascii ouput """ global FAST_JSON if output == 'json': content = "application/json;charset=UTF-8" if error: info = {'status': False, 'error': error} elif data is None: info = {'status': True} else: if hasattr(data, '__iter__') and not keyword: info = data else: info = {keyword: data} if FAST_JSON: # First try the faster standard json encoder try: response = json.dumps(info) except UnicodeDecodeError: FAST_JSON = False logging.info('Switching to slow and safe JSON encoder') if not FAST_JSON: # Use the slower, but safer encoder response = JsonWriter().write(info) if callback: response = '%s(%s)' % (callback, response) elif output == 'xml': if not keyword: # xml always needs an outer keyword, even when json doesn't keyword = 'result' content = "text/xml" xmlmaker = xml_factory() if error: status_str = xmlmaker.run('result', {'status': False, 'error': error}) elif data is None: status_str = xmlmaker.run('result', {'status': True}) else: status_str = xmlmaker.run(keyword, data) response = '\n%s\n' % status_str else: content = "text/plain" if error: response = "error: %s\n" % error elif compat or data is None: response = 'ok\n' else: if type(data) in (list, tuple): # Special handling for list/tuple (backward compatibility) data = [str(val) for val in data] data = ' '.join(data) if isinstance(data, unicode): response = u'%s\n' % data else: response = '%s\n' % str(data) cherrypy.response.headers['Content-Type'] = content cherrypy.response.headers['Pragma'] = 'no-cache' return response class xml_factory(object): """ Recursive xml string maker. Feed it a mixed tuple/dict/item object and will output into an xml string Current limitations: In Two tiered lists hard-coded name of "item": In Three tiered lists hard-coded name of "slot": """ def __init__(self): self.__text = '' def _tuple(self, keyw, lst): text = [] for item in lst: text.append(self.run(keyw, item)) return ''.join(text) def _dict(self, keyw, lst): text = [] for key in lst.keys(): text.append(self.run(key, lst[key])) if keyw: return '<%s>%s\n' % (keyw, ''.join(text), keyw) else: return '' def _list(self, keyw, lst): text = [] for cat in lst: if isinstance(cat, dict): text.append(self._dict(plural_to_single(keyw, 'slot'), cat)) elif isinstance(cat, list): text.append(self._list(plural_to_single(keyw, 'list'), cat)) elif isinstance(cat, tuple): text.append(self._tuple(plural_to_single(keyw, 'tuple'), cat)) else: if not isinstance(cat, basestring): cat = str(cat) name = plural_to_single(keyw, 'item') text.append('<%s>%s\n' % (name, xml_name(cat, encoding='utf-8'), name)) if keyw: return '<%s>%s\n' % (keyw, ''.join(text), keyw) else: return '' def run(self, keyw, lst): if isinstance(lst, dict): text = self._dict(keyw, lst) elif isinstance(lst, list): text = self._list(keyw, lst) elif isinstance(lst, tuple): text = self._tuple(keyw, lst) elif keyw: text = '<%s>%s\n' % (keyw, xml_name(lst, encoding='utf-8'), keyw) else: text = '' return text def handle_server_api(output, kwargs): """ Special handler for API-call 'set_config' [servers] """ name = kwargs.get('keyword') if not name: name = kwargs.get('name') if name: server = config.get_config('servers', name) if server: server.set_dict(kwargs) old_name = name else: config.ConfigServer(name, kwargs) old_name = None Downloader.do.update_server(old_name, name) return name def handle_rss_api(output, kwargs): """ Special handler for API-call 'set_config' [rss] """ name = kwargs.get('keyword') if not name: name = kwargs.get('name') if not name: return None feed = config.get_config('rss', name) if feed: feed.set_dict(kwargs) else: config.ConfigRSS(name, kwargs) return name def handle_cat_api(output, kwargs): """ Special handler for API-call 'set_config' [categories] """ name = kwargs.get('keyword') if not name: name = kwargs.get('name') if not name: return None feed = config.get_config('categories', name) if feed: feed.set_dict(kwargs) else: config.ConfigCat(name, kwargs) return name def build_status(skip_dashboard=False, output=None): # build up header full of basic information info = build_header() info['logfile'] = sabnzbd.LOGFILE info['weblogfile'] = sabnzbd.WEBLOGFILE info['loglevel'] = str(cfg.log_level()) info['folders'] = [xml_name(item) for item in NzbQueue.do.scan_jobs(all=False, action=False)] info['configfn'] = xml_name(config.get_filename()) # Dashboard: Speed of System info['cpumodel'] = getcpu() info['pystone'] = sabnzbd.PYSTONE_SCORE # Dashboard: Speed of Download directory: info['downloaddir'] = sabnzbd.cfg.download_dir.get_path() info['downloaddirspeed'] = sabnzbd.DOWNLOAD_DIR_SPEED # Dashboard: Speed of Complete directory: info['completedir'] = sabnzbd.cfg.complete_dir.get_path() info['completedirspeed'] = sabnzbd.COMPLETE_DIR_SPEED # Dashboard: Connection information if not int_conv(skip_dashboard): info['localipv4'] = localipv4() info['publicipv4'] = publicipv4() info['ipv6'] = ipv6() # Dashboard: DNS-check try: getipaddress.addresslookup(cfg.selftest_host()) info['dnslookup'] = "OK" except: info['dnslookup'] = None info['servers'] = [] servers = sorted(Downloader.do.servers[:], key=lambda svr: '%02d%s' % (svr.priority, svr.displayname.lower())) for server in servers: serverconnections = [] connected = 0 for nw in server.idle_threads[:]: if nw.connected: connected += 1 for nw in server.busy_threads[:]: article = nw.article art_name = "" nzf_name = "" nzo_name = "" if article: nzf = article.nzf nzo = nzf.nzo art_name = xml_name(article.article) # filename field is not always present try: nzf_name = xml_name(nzf.filename) except: # attribute error nzf_name = xml_name(nzf.subject) nzo_name = xml_name(nzo.final_name) # For the templates or for JSON if output: thread_info = { 'thrdnum': nw.thrdnum, 'art_name': art_name, 'nzf_name': nzf_name, 'nzo_name': nzo_name } serverconnections.append(thread_info) else: serverconnections.append((nw.thrdnum, art_name, nzf_name, nzo_name)) if nw.connected: connected += 1 if server.warning and not (connected or server.errormsg): connected = unicoder(server.warning) if server.request and not server.info: connected = T(' Resolving address').replace(' ', '') serverconnections.sort() # For the templates or for JSON if output: server_info = { 'servername': server.displayname, 'serveractiveconn': connected, 'servertotalconn': server.threads, 'serverconnections': serverconnections, 'serverssl': server.ssl, 'serversslinfo': server.ssl_info, 'serveractive': server.active, 'servererror': server.errormsg, 'serverpriority': server.priority, 'serveroptional': server.optional } info['servers'].append(server_info) else: info['servers'].append((server.displayname, '', connected, serverconnections, server.ssl, server.active, server.errormsg, server.priority, server.optional)) info['warnings'] = sabnzbd.GUIHANDLER.content() return info def build_queue(start=0, limit=0, trans=False, output=None, search=None): if output: converter = unicoder else: converter = xml_name # build up header full of basic information info, pnfo_list, bytespersec, q_size, bytes_left_previous_page = build_queue_header(search=search, start=start, limit=limit, output=output) datestart = datetime.datetime.now() priorities = {TOP_PRIORITY: 'Force', REPAIR_PRIORITY: 'Repair', HIGH_PRIORITY: 'High', NORMAL_PRIORITY: 'Normal', LOW_PRIORITY: 'Low'} limit = int_conv(limit) start = int_conv(start) info['refresh_rate'] = str(cfg.refresh_rate()) if cfg.refresh_rate() > 0 else '' info['scripts'] = list_scripts() info['categories'] = list_cats(output is None) info['rating_enable'] = bool(cfg.rating_enable()) info['noofslots'] = q_size info['start'] = start info['limit'] = limit info['finish'] = info['start'] + info['limit'] # SMPL-skin specific stuff if info['finish'] > info['noofslots']: info['finish'] = info['noofslots'] info['queue_details'] = '0' if 'queue_details' in cherrypy.request.cookie: info['queue_details'] = str(int_conv(cherrypy.request.cookie['queue_details'].value)) n = start running_bytes = bytes_left_previous_page slotinfo = [] for pnfo in pnfo_list: nzo_id = pnfo.nzo_id bytesleft = pnfo.bytes_left bytes = pnfo.bytes average_date = pnfo.avg_date is_propagating = (pnfo.avg_stamp + float(cfg.propagation_delay() * 60)) > time.time() status = pnfo.status priority = pnfo.priority mbleft = (bytesleft / MEBI) mb = (bytes / MEBI) slot = {'index': n, 'nzo_id': str(nzo_id)} slot['unpackopts'] = str(sabnzbd.opts_to_pp(pnfo.repair, pnfo.unpack, pnfo.delete)) slot['priority'] = priorities[priority] if priority >= LOW_PRIORITY else priorities[NORMAL_PRIORITY] slot['script'] = pnfo.script if pnfo.script else 'None' slot['filename'] = converter(pnfo.filename) slot['password'] = converter(pnfo.password) if pnfo.password else '' slot['cat'] = converter(pnfo.category) if pnfo.category else 'None' slot['mbleft'] = "%.2f" % mbleft slot['mb'] = "%.2f" % mb slot['size'] = format_bytes(bytes) slot['sizeleft'] = format_bytes(bytesleft) slot['percentage'] = "%s" % (int(((mb - mbleft) / mb) * 100)) if mb != mbleft else '0' slot['mbmissing'] = "%.2f" % (pnfo.bytes_missing / MEBI) slot['direct_unpack'] = pnfo.direct_unpack if not output: slot['mb_fmt'] = locale.format('%d', int(mb), True) slot['mbdone_fmt'] = locale.format('%d', int(mb - mbleft), True) if not Downloader.do.paused and status not in (Status.PAUSED, Status.FETCHING, Status.GRABBING): if is_propagating: slot['status'] = Status.PROP elif status == Status.CHECKING: slot['status'] = Status.CHECKING else: slot['status'] = Status.DOWNLOADING else: # Ensure compatibility of API status if status == Status.DELETED or priority == TOP_PRIORITY: status = Status.DOWNLOADING slot['status'] = "%s" % (status) if (Downloader.do.paused or Downloader.do.postproc or is_propagating or \ status not in (Status.DOWNLOADING, Status.FETCHING, Status.QUEUED)) and priority != TOP_PRIORITY: slot['timeleft'] = '0:00:00' slot['eta'] = 'unknown' else: running_bytes += bytesleft slot['timeleft'] = calc_timeleft(running_bytes, bytespersec) try: datestart = datestart + datetime.timedelta(seconds=bytesleft / bytespersec) # new eta format: 16:00 Fri 07 Feb slot['eta'] = datestart.strftime(time_format('%H:%M %a %d %b')).decode(codepage) except: datestart = datetime.datetime.now() slot['eta'] = 'unknown' # Do not show age when it's not known if average_date.year < 2000: slot['avg_age'] = '-' else: slot['avg_age'] = calc_age(average_date, bool(trans)) rating = Rating.do.get_rating_by_nzo(nzo_id) slot['has_rating'] = rating is not None if rating: slot['rating_avg_video'] = rating.avg_video slot['rating_avg_audio'] = rating.avg_audio slotinfo.append(slot) n += 1 if slotinfo: info['slots'] = slotinfo else: info['slots'] = [] return info, pnfo_list, bytespersec def fast_queue(): """ Return paused, bytes_left, bpsnow, time_left """ bytes_left = NzbQueue.do.remaining() paused = Downloader.do.paused bpsnow = BPSMeter.do.get_bps() time_left = calc_timeleft(bytes_left, bpsnow) return paused, bytes_left, bpsnow, time_left def build_file_list(nzo_id): """ Build file lists for specified job """ jobs = [] nzo = NzbQueue.do.get_nzo(nzo_id) if nzo: pnfo = nzo.gather_info(full=True) finished_files = pnfo.finished_files active_files = pnfo.active_files queued_files = pnfo.queued_files for nzf in finished_files: jobs.append({'filename': xml_name(nzf.filename if nzf.filename else nzf.subject), 'mbleft': "%.2f" % (nzf.bytes_left / MEBI), 'mb': "%.2f" % (nzf.bytes / MEBI), 'bytes': "%.2f" % nzf.bytes, 'age': calc_age(nzf.date), 'nzf_id': nzf.nzf_id, 'status': 'finished'}) for nzf in active_files: jobs.append({'filename': xml_name(nzf.filename if nzf.filename else nzf.subject), 'mbleft': "%.2f" % (nzf.bytes_left / MEBI), 'mb': "%.2f" % (nzf.bytes / MEBI), 'bytes': "%.2f" % nzf.bytes, 'age': calc_age(nzf.date), 'nzf_id': nzf.nzf_id, 'status': 'active'}) for nzf in queued_files: jobs.append({'filename': xml_name(nzf.filename if nzf.filename else nzf.subject), 'set': xml_name(nzf.setname), 'mbleft': "%.2f" % (nzf.bytes_left / MEBI), 'mb': "%.2f" % (nzf.bytes / MEBI), 'bytes': "%.2f" % nzf.bytes, 'age': calc_age(nzf.date), 'nzf_id': nzf.nzf_id, 'status': 'queued'}) return jobs def rss_qstatus(): """ Return a RSS feed with the queue status """ qnfo = NzbQueue.do.queue_info() pnfo_list = qnfo.list rss = RSS() rss.channel.title = "SABnzbd Queue" rss.channel.description = "Overview of current downloads" rss.channel.link = "http://%s:%s%s/queue" % (cfg.cherryhost(), cfg.cherryport(), cfg.url_base()) rss.channel.language = "en" item = Item() item.title = 'Total ETA: %s - Queued: %.2f MB - Speed: %.2f kB/s' % \ ( calc_timeleft(qnfo.bytes_left, BPSMeter.do.get_bps()), qnfo.bytes_left / MEBI, BPSMeter.do.get_bps() / KIBI ) rss.addItem(item) sum_bytesleft = 0 for pnfo in pnfo_list: filename = pnfo.filename bytesleft = pnfo.bytes_left / MEBI bytes = pnfo.bytes / MEBI mbleft = (bytesleft / MEBI) mb = (bytes / MEBI) nzo_id = pnfo.nzo_id if mb == mbleft: percentage = "0%" else: percentage = "%s%%" % (int(((mb - mbleft) / mb) * 100)) filename = xml_name(filename) name = u'%s (%s)' % (filename, percentage) item = Item() item.title = name item.link = "http://%s:%s%s/history" % (cfg.cherryhost(), cfg.cherryport(), cfg.url_base()) item.guid = nzo_id status_line = [] status_line.append('') # Total MB/MB left status_line.append('
Remain/Total: %.2f/%.2f MB
' % (bytesleft, bytes)) # ETA sum_bytesleft += pnfo.bytes_left status_line.append("
ETA: %s
" % calc_timeleft(sum_bytesleft, BPSMeter.do.get_bps())) status_line.append("
Age: %s
" % calc_age(pnfo.avg_date)) status_line.append("") item.description = ''.join(status_line) rss.addItem(item) rss.channel.lastBuildDate = std_time(time.time()) rss.channel.pubDate = rss.channel.lastBuildDate rss.channel.ttl = "1" return rss.write() def options_list(output): return report(output, keyword='options', data={ 'yenc': sabnzbd.decoder.HAVE_YENC, 'par2': sabnzbd.newsunpack.PAR2_COMMAND, 'multipar': sabnzbd.newsunpack.MULTIPAR_COMMAND, 'rar': sabnzbd.newsunpack.RAR_COMMAND, 'zip': sabnzbd.newsunpack.ZIP_COMMAND, '7zip': sabnzbd.newsunpack.SEVEN_COMMAND, 'nice': sabnzbd.newsunpack.NICE_COMMAND, 'ionice': sabnzbd.newsunpack.IONICE_COMMAND }) def retry_job(job, new_nzb, password): """ Re enter failed job in the download queue """ if job: history_db = sabnzbd.connect_db() futuretype, url, pp, script, cat = history_db.get_other(job) if futuretype: if pp == 'X': pp = None sabnzbd.add_url(url, pp, script, cat) history_db.remove_history(job) else: path = history_db.get_path(job) if path: nzo_id = NzbQueue.do.repair_job(platform_encode(path), new_nzb, password) history_db.remove_history(job) return nzo_id return None def retry_all_jobs(): """ Re enter all failed jobs in the download queue """ history_db = sabnzbd.connect_db() return NzbQueue.do.retry_all_jobs(history_db) def del_job_files(job_paths): """ Remove files of each path in the list """ for path in job_paths: if path and clip_path(path).lower().startswith(cfg.download_dir.get_path().lower()): remove_all(path, recursive=True) def del_hist_job(job, del_files): """ Remove history element """ if job: path = PostProcessor.do.get_path(job) if path: PostProcessor.do.delete(job, del_files=del_files) else: history_db = sabnzbd.connect_db() path = history_db.get_path(job) history_db.remove_history(job) if path and del_files and clip_path(path).lower().startswith(cfg.download_dir.get_path().lower()): remove_all(path, recursive=True) return True def Tspec(txt): """ Translate special terms """ if txt == 'None': return T('None') elif txt in ('Default', '*'): return T('Default') else: return txt _SKIN_CACHE = {} # Stores pre-translated acronyms # This special is to be used in interface.py for template processing # to be passed for the $T function: so { ..., 'T' : Ttemplate, ...} def Ttemplate(txt): """ Translation function for Skin texts """ global _SKIN_CACHE if txt in _SKIN_CACHE: return _SKIN_CACHE[txt] else: tra = html_escape(Tx(SKIN_TEXT.get(txt, txt))) _SKIN_CACHE[txt] = tra return tra def clear_trans_cache(): """ Clean cache for skin translations """ global _SKIN_CACHE dummy = _SKIN_CACHE _SKIN_CACHE = {} del dummy sabnzbd.WEBUI_READY = True def build_header(webdir='', output=None): """ Build the basic header """ try: uptime = calc_age(sabnzbd.START) except: uptime = "-" speed_limit = Downloader.do.get_limit() if speed_limit <= 0: speed_limit = 100 speed_limit_abs = Downloader.do.get_limit_abs() if speed_limit_abs <= 0: speed_limit_abs = '' diskspace_info = diskspace() header = {} # We don't output everything for API if not output: header['T'] = Ttemplate header['Tspec'] = Tspec header['Tx'] = Ttemplate header['uptime'] = uptime header['color_scheme'] = sabnzbd.WEB_COLOR or '' header['helpuri'] = 'https://sabnzbd.org/wiki/' header['restart_req'] = sabnzbd.RESTART_REQ header['pid'] = os.getpid() header['active_lang'] = cfg.language() header['my_lcldata'] = sabnzbd.DIR_LCLDATA header['my_home'] = sabnzbd.DIR_HOME header['webdir'] = webdir or sabnzbd.WEB_DIR header['url_base'] = cfg.url_base() header['nt'] = sabnzbd.WIN32 header['darwin'] = sabnzbd.DARWIN header['power_options'] = sabnzbd.WIN32 or sabnzbd.DARWIN or sabnzbd.LINUX_POWER header['pp_pause_event'] = sabnzbd.scheduler.pp_pause_event() header['session'] = cfg.api_key() header['new_release'], header['new_rel_url'] = sabnzbd.NEW_VERSION header['version'] = sabnzbd.__version__ header['paused'] = Downloader.do.paused or Downloader.do.postproc header['pause_int'] = scheduler.pause_int() header['paused_all'] = sabnzbd.PAUSED_ALL header['diskspace1'] = "%.2f" % diskspace_info['download_dir'][1] header['diskspace2'] = "%.2f" % diskspace_info['complete_dir'][1] header['diskspace1_norm'] = to_units(diskspace_info['download_dir'][1] * GIGI) header['diskspace2_norm'] = to_units(diskspace_info['complete_dir'][1] * GIGI) header['diskspacetotal1'] = "%.2f" % diskspace_info['download_dir'][0] header['diskspacetotal2'] = "%.2f" % diskspace_info['complete_dir'][0] header['loadavg'] = loadavg() header['speedlimit'] = "{1:0.{0}f}".format(int(speed_limit % 1 > 0), speed_limit) header['speedlimit_abs'] = "%s" % speed_limit_abs header['have_warnings'] = str(sabnzbd.GUIHANDLER.count()) header['finishaction'] = sabnzbd.QUEUECOMPLETE header['quota'] = to_units(BPSMeter.do.quota) header['have_quota'] = bool(BPSMeter.do.quota > 0.0) header['left_quota'] = to_units(BPSMeter.do.left) anfo = ArticleCache.do.cache_info() header['cache_art'] = str(anfo.article_sum) header['cache_size'] = format_bytes(anfo.cache_size) header['cache_max'] = str(anfo.cache_limit) return header def build_queue_header(search=None, start=0, limit=0, output=None): """ Build full queue header """ header = build_header(output=output) bytespersec = BPSMeter.do.get_bps() qnfo = NzbQueue.do.queue_info(search=search, start=start, limit=limit) bytesleft = qnfo.bytes_left bytes = qnfo.bytes header['kbpersec'] = "%.2f" % (bytespersec / KIBI) header['speed'] = to_units(bytespersec, spaces=1) header['mbleft'] = "%.2f" % (bytesleft / MEBI) header['mb'] = "%.2f" % (bytes / MEBI) header['sizeleft'] = format_bytes(bytesleft) header['size'] = format_bytes(bytes) header['noofslots_total'] = qnfo.q_fullsize status = '' if Downloader.do.paused or Downloader.do.postproc: status = Status.PAUSED elif bytespersec > 0: status = Status.DOWNLOADING else: status = 'Idle' header['status'] = status header['timeleft'] = calc_timeleft(bytesleft, bytespersec) try: datestart = datetime.datetime.now() + datetime.timedelta(seconds=bytesleft / bytespersec) # new eta format: 16:00 Fri 07 Feb header['eta'] = datestart.strftime(time_format('%H:%M %a %d %b')).decode(codepage) except: datestart = datetime.datetime.now() header['eta'] = T('unknown') return (header, qnfo.list, bytespersec, qnfo.q_fullsize, qnfo.bytes_left_previous_page) def build_history(start=None, limit=None, verbose=False, verbose_list=None, search=None, failed_only=0, categories=None, output=None): if output: converter = unicoder else: converter = xml_name if not verbose_list: verbose_list = [] limit = int_conv(limit) if not limit: limit = 1000000 start = int_conv(start) failed_only = int_conv(failed_only) def matches_search(text, search_text): # Replace * with .* and ' ' with . search_text = search_text.strip().replace('*', '.*').replace(' ', '.*') + '.*?' try: re_search = re.compile(search_text, re.I) except: logging.error(T('Failed to compile regex for search term: %s'), search_text) return False return re_search.search(text) # Grab any items that are active or queued in postproc queue = PostProcessor.do.get_queue() # Filter out any items that don't match the search if search: queue = [nzo for nzo in queue if matches_search(nzo.final_name, search)] # Multi-page support for postproc items full_queue_size = len(queue) if start > full_queue_size: # On a page where we shouldn't show postproc items queue = [] h_limit = limit else: try: if limit: queue = queue[start:start + limit] else: queue = queue[start:] except: pass # Remove the amount of postproc items from the db request for history items h_limit = max(limit - len(queue), 0) h_start = max(start - full_queue_size, 0) # Aquire the db instance try: history_db = sabnzbd.connect_db() close_db = False except: # Required for repairs at startup because Cherrypy isn't active yet history_db = HistoryDB() close_db = True # Fetch history items if not h_limit: items, fetched_items, total_items = history_db.fetch_history(h_start, 1, search, failed_only, categories) items = [] fetched_items = 0 else: items, fetched_items, total_items = history_db.fetch_history(h_start, h_limit, search, failed_only, categories) # Fetch which items should show details from the cookie k = [] if verbose: details_show_all = True else: details_show_all = False cookie = cherrypy.request.cookie if 'history_verbosity' in cookie: k = cookie['history_verbosity'].value if k == 'all': details_show_all = True k = k.split(',') k.extend(verbose_list) # Reverse the queue to add items to the top (faster than insert) items.reverse() # Add the postproc items to the top of the history items = get_active_history(queue, items) # Unreverse the queue items.reverse() retry_folders = [] for item in items: for key in item: value = item[key] if isinstance(value, basestring): item[key] = converter(value) if details_show_all: item['show_details'] = 'True' else: if item['nzo_id'] in k: item['show_details'] = 'True' else: item['show_details'] = '' if item['bytes']: item['size'] = format_bytes(item['bytes']) else: item['size'] = '' if 'loaded' not in item: item['loaded'] = False path = platform_encode(item.get('path', '')) item['retry'] = int(bool(item.get('status') == 'Failed' and path and path not in retry_folders and starts_with_path(path, cfg.download_dir.get_path()) and os.path.exists(path)) and not bool(globber(os.path.join(path, JOB_ADMIN), 'SABnzbd_n*')) ) if item['report'] == 'future': item['retry'] = True if item['retry']: retry_folders.append(path) if Rating.do: rating = Rating.do.get_rating_by_nzo(item['nzo_id']) else: rating = None item['has_rating'] = rating is not None if rating: item['rating_avg_video'] = rating.avg_video item['rating_avg_audio'] = rating.avg_audio item['rating_avg_vote_up'] = rating.avg_vote_up item['rating_avg_vote_down'] = rating.avg_vote_down item['rating_user_video'] = rating.user_video item['rating_user_audio'] = rating.user_audio item['rating_user_vote'] = rating.user_vote total_items += full_queue_size fetched_items = len(items) if close_db: history_db.close() return (items, fetched_items, total_items) def get_active_history(queue=None, items=None): """ Get the currently in progress and active history queue. """ if items is None: items = [] if queue is None: queue = PostProcessor.do.get_queue() for nzo in queue: history = build_history_info(nzo) item = {} item['completed'], item['name'], item['nzb_name'], item['category'], item['pp'], item['script'], item['report'], \ item['url'], item['status'], item['nzo_id'], item['storage'], item['path'], item['script_log'], \ item['script_line'], item['download_time'], item['postproc_time'], item['stage_log'], \ item['downloaded'], item['completeness'], item['fail_message'], item['url_info'], item['bytes'], \ dummy, dummy, item['password'] = history item['action_line'] = nzo.action_line item = unpack_history_info(item) item['loaded'] = nzo.pp_active if item['bytes']: item['size'] = format_bytes(item['bytes']) else: item['size'] = '' # Queue display needs Unicode instead of UTF-8 for kw in item: if isinstance(item[kw], str): item[kw] = item[kw].decode('utf-8') items.append(item) return items def format_bytes(bytes): b = to_units(bytes) if b == '': return b else: return b + 'B' def calc_timeleft(bytesleft, bps): """ Calculate the time left in the format HH:MM:SS """ try: if bytesleft <= 0: return '0:00:00' totalseconds = int(bytesleft / bps) minutes, seconds = divmod(totalseconds, 60) hours, minutes = divmod(minutes, 60) days, hours = divmod(hours, 24) if minutes < 10: minutes = '0%s' % minutes if seconds < 10: seconds = '0%s' % seconds if days > 0: if hours < 10: hours = '0%s' % hours return '%s:%s:%s:%s' % (days, hours, minutes, seconds) else: return '%s:%s:%s' % (hours, minutes, seconds) except: return '0:00:00' def std_time(when): # Fri, 16 Nov 2007 16:42:01 GMT +0100 item = time.strftime(time_format('%a, %d %b %Y %H:%M:%S'), time.localtime(when)).decode(codepage) item += " GMT %+05d" % (-time.timezone / 36) return item def list_scripts(default=False, none=True): """ Return a list of script names, optionally with 'Default' added """ lst = [] path = cfg.script_dir.get_path() if path and os.access(path, os.R_OK): for script in globber_full(path): if os.path.isfile(script): if (sabnzbd.WIN32 and os.path.splitext(script)[1].lower() in PATHEXT and not win32api.GetFileAttributes(script) & win32file.FILE_ATTRIBUTE_HIDDEN) or \ script.endswith('.py') or \ (not sabnzbd.WIN32 and userxbit(script) and not os.path.basename(script).startswith('.')): lst.append(os.path.basename(script)) if none: lst.insert(0, 'None') if default: lst.insert(0, 'Default') return lst def list_cats(default=True): """ Return list of (ordered) categories, when default==False use '*' for Default category """ lst = [cat['name'] for cat in config.get_ordered_categories()] if default: lst.remove('*') lst.insert(0, 'Default') return lst def remove_callable(dic): """ Remove all callable items from dictionary """ for key, value in dic.items(): if callable(value): del dic[key] return dic _PLURAL_TO_SINGLE = { 'categories': 'category', 'servers': 'server', 'rss': 'feed', 'scripts': 'script', 'warnings': 'warning', 'files': 'file', 'jobs': 'job' } def plural_to_single(kw, def_kw=''): try: return _PLURAL_TO_SINGLE[kw] except KeyError: return def_kw def del_from_section(kwargs): """ Remove keyword in section """ section = kwargs.get('section', '') if section in ('servers', 'rss', 'categories'): keyword = kwargs.get('keyword') if keyword: item = config.get_config(section, keyword) if item: item.delete() del item config.save_config() if section == 'servers': Downloader.do.update_server(keyword, None) return True else: return False def history_remove_failed(): """ Remove all failed jobs from history, including files """ logging.info('Scheduled removal of all failed jobs') history_db = HistoryDB() del_job_files(history_db.get_failed_paths()) history_db.remove_failed() history_db.close() del history_db def history_remove_completed(): """ Remove all completed jobs from history """ logging.info('Scheduled removal of all completed jobs') history_db = HistoryDB() history_db.remove_completed() history_db.close() del history_db SABnzbd-2.3.2/sabnzbd/articlecache.py0000644000000000000000000001504413217005257015541 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.articlecache - Article cache handling """ import sys import logging import threading import struct import sabnzbd from sabnzbd.decorators import synchronized from sabnzbd.constants import GIGI, ANFO ARTICLE_LOCK = threading.Lock() class ArticleCache(object): do = None def __init__(self): self.__cache_limit_org = 0 self.__cache_limit = 0 self.__cache_size = 0 self.__article_list = [] # List of buffered articles self.__article_table = {} # Dict of buffered articles # On 32 bit we only allow the user to set 1GB # For 64 bit we allow up to 4GB, in case somebody wants that self.__cache_upper_limit = GIGI if sabnzbd.DARWIN or sabnzbd.WIN64 or (struct.calcsize("P") * 8) == 64: self.__cache_upper_limit = 4*GIGI ArticleCache.do = self @synchronized(ARTICLE_LOCK) def cache_info(self): return ANFO(len(self.__article_list), abs(self.__cache_size), self.__cache_limit_org) @synchronized(ARTICLE_LOCK) def new_limit(self, limit): """ Called when cache limit changes """ self.__cache_limit_org = limit if limit < 0: self.__cache_limit = self.__cache_upper_limit else: self.__cache_limit = min(limit, self.__cache_upper_limit) @synchronized(ARTICLE_LOCK) def reserve_space(self, data): """ Is there space left in the set limit? """ data_size = sys.getsizeof(data) * 64 self.__cache_size += data_size if self.__cache_size + data_size > self.__cache_limit: return False else: return True @synchronized(ARTICLE_LOCK) def free_reserve_space(self, data): """ Remove previously reserved space """ data_size = sys.getsizeof(data) * 64 self.__cache_size -= data_size return self.__cache_size + data_size < self.__cache_limit @synchronized(ARTICLE_LOCK) def save_article(self, article, data): if article.nzf.nzo.is_gone(): # Do not discard this article because the # file might still be processed at this moment!! return # Register article if article not in article.nzf.nzo.saved_articles: article.nzf.nzo.saved_articles.append(article) if article.lowest_partnum and not article.nzf.import_finished: # Write the first-fetched articles to disk # Otherwise the cache could overflow self.__flush_article(article, data) return if self.__cache_limit: if self.__cache_limit < 0: self.__add_to_cache(article, data) else: data_size = len(data) while (self.__cache_size > (self.__cache_limit - data_size)) \ and self.__article_list: # Flush oldest article in cache old_article = self.__article_list.pop(0) old_data = self.__article_table.pop(old_article) self.__cache_size -= len(old_data) # No need to flush if this is a refreshment article if old_article != article: self.__flush_article(old_article, old_data) # Does our article fit into our limit now? if (self.__cache_size + data_size) <= self.__cache_limit: self.__add_to_cache(article, data) else: self.__flush_article(article, data) else: self.__flush_article(article, data) @synchronized(ARTICLE_LOCK) def load_article(self, article): data = None nzo = article.nzf.nzo if article in self.__article_list: data = self.__article_table.pop(article) self.__article_list.remove(article) self.__cache_size -= len(data) elif article.art_id: data = sabnzbd.load_data(article.art_id, nzo.workpath, remove=True, do_pickle=False, silent=True) if article in nzo.saved_articles: nzo.remove_saved_article(article) return data @synchronized(ARTICLE_LOCK) def flush_articles(self): self.__cache_size = 0 while self.__article_list: article = self.__article_list.pop(0) data = self.__article_table.pop(article) self.__flush_article(article, data) @synchronized(ARTICLE_LOCK) def purge_articles(self, articles): for article in articles: if article in self.__article_list: self.__article_list.remove(article) data = self.__article_table.pop(article) self.__cache_size -= len(data) if article.art_id: sabnzbd.remove_data(article.art_id, article.nzf.nzo.workpath) def __flush_article(self, article, data): nzf = article.nzf nzo = nzf.nzo if nzo.is_gone(): # Do not discard this article because the # file might still be processed at this moment!! return art_id = article.get_art_id() if art_id: # Save data, but don't complain when destination folder is missing # because this flush may come after completion of the NZO. sabnzbd.save_data(data, art_id, nzo.workpath, do_pickle=False, silent=True) else: logging.warning("Flushing %s failed -> no art_id", article) def __add_to_cache(self, article, data): if article in self.__article_table: self.__cache_size -= len(self.__article_table[article]) else: self.__article_list.append(article) self.__article_table[article] = data self.__cache_size += len(data) # Create the instance ArticleCache() SABnzbd-2.3.2/sabnzbd/assembler.py0000644000000000000000000004126613217005257015114 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.assembler - threaded assembly/decoding of files """ import os import Queue import logging import re from threading import Thread from time import sleep import hashlib import sabnzbd from sabnzbd.misc import get_filepath, sanitize_filename, get_unique_filename, renamer, \ set_permissions, long_path, clip_path, has_win_device, get_all_passwords, diskspace, \ get_filename, get_ext from sabnzbd.constants import Status, GIGI import sabnzbd.cfg as cfg from sabnzbd.articlecache import ArticleCache from sabnzbd.postproc import PostProcessor import sabnzbd.downloader import sabnzbd.par2file as par2file import sabnzbd.utils.rarfile as rarfile from sabnzbd.encoding import unicoder from sabnzbd.rating import Rating class Assembler(Thread): do = None # Link to the instance of this method def __init__(self, queue=None): Thread.__init__(self) if queue: self.queue = queue else: self.queue = Queue.Queue() Assembler.do = self def stop(self): self.process(None) def process(self, job): self.queue.put(job) def run(self): while 1: job = self.queue.get() if not job: logging.info("Shutting down") break nzo, nzf = job if nzf: # Check if enough disk space is free, if not pause downloader and send email if diskspace(force=True)['download_dir'][1] < (cfg.download_free.get_float() + nzf.bytes) / GIGI: # Only warn and email once if not sabnzbd.downloader.Downloader.do.paused: logging.warning(T('Too little diskspace forcing PAUSE')) # Pause downloader, but don't save, since the disk is almost full! sabnzbd.downloader.Downloader.do.pause() sabnzbd.emailer.diskfull() # Abort all direct unpackers, just to be sure sabnzbd.directunpacker.abort_all() # Place job back in queue and wait 30 seconds to hope it gets resolved self.process(job) sleep(30) continue # Prepare filename nzo.verify_nzf_filename(nzf) nzf.filename = sanitize_filename(nzf.filename) filepath = get_filepath(long_path(cfg.download_dir.get_path()), nzo, nzf.filename) nzf.filename = get_filename(filepath) if filepath: logging.info('Decoding %s %s', filepath, nzf.type) try: filepath = self.assemble(nzf, filepath) except IOError, (errno, strerror): # If job was deleted or in active post-processing, ignore error if not nzo.deleted and not nzo.is_gone() and not nzo.pp_active: # 28 == disk full => pause downloader if errno == 28: logging.error(T('Disk full! Forcing Pause')) else: logging.error(T('Disk error on creating file %s'), clip_path(filepath)) # Log traceback logging.info('Traceback: ', exc_info=True) # Pause without saving sabnzbd.downloader.Downloader.do.pause() continue except: logging.error(T('Fatal error in Assembler'), exc_info=True) break # Clean-up admin data nzf.remove_admin() # Do rar-related processing if rarfile.is_rarfile(filepath): # Encryption and unwanted extension detection rar_encrypted, unwanted_file = check_encrypted_and_unwanted_files(nzo, filepath) if rar_encrypted: if cfg.pause_on_pwrar() == 1: logging.warning(remove_warning_label(T('WARNING: Paused job "%s" because of encrypted RAR file (if supplied, all passwords were tried)')), nzo.final_name) nzo.pause() else: logging.warning(remove_warning_label(T('WARNING: Aborted job "%s" because of encrypted RAR file (if supplied, all passwords were tried)')), nzo.final_name) nzo.fail_msg = T('Aborted, encryption detected') sabnzbd.nzbqueue.NzbQueue.do.end_job(nzo) if unwanted_file: logging.warning(remove_warning_label(T('WARNING: In "%s" unwanted extension in RAR file. Unwanted file is %s ')), nzo.final_name, unwanted_file) logging.debug(T('Unwanted extension is in rar file %s'), filepath) if cfg.action_on_unwanted_extensions() == 1 and nzo.unwanted_ext == 0: logging.debug('Unwanted extension ... pausing') nzo.unwanted_ext = 1 nzo.pause() if cfg.action_on_unwanted_extensions() == 2: logging.debug('Unwanted extension ... aborting') nzo.fail_msg = T('Aborted, unwanted extension detected') sabnzbd.nzbqueue.NzbQueue.do.end_job(nzo) # Add to direct unpack nzo.add_to_direct_unpacker(nzf) elif par2file.is_parfile(filepath): # Parse par2 files, cloaked or not nzo.handle_par2(nzf, filepath) filter, reason = nzo_filtered_by_rating(nzo) if filter == 1: logging.warning(remove_warning_label(T('WARNING: Paused job "%s" because of rating (%s)')), nzo.final_name, reason) nzo.pause() elif filter == 2: logging.warning(remove_warning_label(T('WARNING: Aborted job "%s" because of rating (%s)')), nzo.final_name, reason) nzo.fail_msg = T('Aborted, rating filter matched (%s)') % reason sabnzbd.nzbqueue.NzbQueue.do.end_job(nzo) else: sabnzbd.nzbqueue.NzbQueue.do.remove(nzo.nzo_id, add_to_history=False, cleanup=False) PostProcessor.do.process(nzo) def assemble(self, nzf, path): """ Assemble a NZF from its table of articles """ md5 = hashlib.md5() fout = open(path, 'ab') decodetable = nzf.decodetable for articlenum in decodetable: # Break if deleted during writing if nzf.nzo.status is Status.DELETED: break # Sleep to allow decoder/assembler switching sleep(0.0001) article = decodetable[articlenum] data = ArticleCache.do.load_article(article) if not data: logging.info(T('%s missing'), article) else: # yenc data already decoded, flush it out fout.write(data) md5.update(data) fout.flush() fout.close() set_permissions(path) nzf.md5sum = md5.digest() del md5 return path def file_has_articles(nzf): """ Do a quick check to see if any articles are present for this file. Destructive: only to be used to differentiate between unknown encoding and no articles. """ has = False decodetable = nzf.decodetable for articlenum in decodetable: sleep(0.01) article = decodetable[articlenum] data = ArticleCache.do.load_article(article) if data: has = True return has RE_SUBS = re.compile(r'\W+sub|subs|subpack|subtitle|subtitles(?![a-z])', re.I) def is_cloaked(nzo, path, names): """ Return True if this is likely to be a cloaked encrypted post """ fname = unicoder(get_filename(path)).lower() fname = os.path.splitext(fname)[0] for name in names: name = get_filename(name.lower()) name, ext = os.path.splitext(unicoder(name)) if ext == u'.rar' and fname.startswith(name) and (len(fname) - len(name)) < 8 and len(names) < 3 and not RE_SUBS.search(fname): # Only warn once if nzo.encrypted == 0: logging.warning(T('Job "%s" is probably encrypted due to RAR with same name inside this RAR'), nzo.final_name) nzo.encrypted = 1 return True elif 'password' in name: # Only warn once if nzo.encrypted == 0: logging.warning(T('Job "%s" is probably encrypted: "password" in filename "%s"'), nzo.final_name, name) nzo.encrypted = 1 return True return False def check_encrypted_and_unwanted_files(nzo, filepath): """ Combines check for unwanted and encrypted files to save on CPU and IO """ encrypted = False unwanted = None if (cfg.unwanted_extensions() and cfg.action_on_unwanted_extensions()) or (nzo.encrypted == 0 and cfg.pause_on_pwrar()): # These checks should not break the assembler try: # Rarfile freezes on Windows special names, so don't try those! if sabnzbd.WIN32 and has_win_device(filepath): return encrypted, unwanted # Is it even a rarfile? if rarfile.is_rarfile(filepath): # Open the rar rarfile.UNRAR_TOOL = sabnzbd.newsunpack.RAR_COMMAND zf = rarfile.RarFile(filepath, all_names=True) # Check for encryption if nzo.encrypted == 0 and cfg.pause_on_pwrar() and (zf.needs_password() or is_cloaked(nzo, filepath, zf.namelist())): # Load all passwords passwords = get_all_passwords(nzo) # Cloaked job? if is_cloaked(nzo, filepath, zf.namelist()): encrypted = True elif not sabnzbd.HAVE_CRYPTOGRAPHY and not passwords: # if no cryptography installed, only error when no password was set logging.info(T('%s missing'), 'Python Cryptography') nzo.encrypted = 1 encrypted = True elif sabnzbd.HAVE_CRYPTOGRAPHY: # Lets test if any of the password work password_hit = False for password in passwords: if password: logging.info('Trying password "%s" on job "%s"', password, nzo.final_name) try: zf.setpassword(password) except: # On weird passwords the setpassword() will fail # but the actual rartest() will work pass try: zf.testrar() password_hit = password break except rarfile.RarCRCError: # On CRC error we can continue! password_hit = password break except Exception as e: # Did we start from the right volume? if 'need to start extraction from a previous volume' in e[0]: return encrypted, unwanted # This one failed pass # Did any work? if password_hit: # We always trust the user's input if not nzo.password: nzo.password = password_hit # Don't check other files logging.info('Password "%s" matches for job "%s"', password_hit, nzo.final_name) nzo.encrypted = -1 encrypted = False else: # Encrypted and none of them worked nzo.encrypted = 1 encrypted = True else: # Don't check other files nzo.encrypted = -1 encrypted = False # Check for unwanted extensions if cfg.unwanted_extensions() and cfg.action_on_unwanted_extensions(): for somefile in zf.namelist(): logging.debug('File contains: %s', somefile) if get_ext(somefile).replace('.', '').lower() in cfg.unwanted_extensions(): logging.debug('Unwanted file %s', somefile) unwanted = somefile zf.close() del zf except: logging.info('Error during inspection of RAR-file %s', filepath) logging.debug('Traceback: ', exc_info=True) return encrypted, unwanted def nzo_filtered_by_rating(nzo): if Rating.do and cfg.rating_enable() and cfg.rating_filter_enable() and (nzo.rating_filtered < 2): rating = Rating.do.get_rating_by_nzo(nzo.nzo_id) if rating is not None: nzo.rating_filtered = 1 reason = rating_filtered(rating, nzo.filename.lower(), True) if reason is not None: return (2, reason) reason = rating_filtered(rating, nzo.filename.lower(), False) if reason is not None: return (1, reason) return (0, "") def rating_filtered(rating, filename, abort): def check_keyword(keyword): clean_keyword = keyword.strip().lower() return (len(clean_keyword) > 0) and (clean_keyword in filename) audio = cfg.rating_filter_abort_audio() if abort else cfg.rating_filter_pause_audio() video = cfg.rating_filter_abort_video() if abort else cfg.rating_filter_pause_video() spam = cfg.rating_filter_abort_spam() if abort else cfg.rating_filter_pause_spam() spam_confirm = cfg.rating_filter_abort_spam_confirm() if abort else cfg.rating_filter_pause_spam_confirm() encrypted = cfg.rating_filter_abort_encrypted() if abort else cfg.rating_filter_pause_encrypted() encrypted_confirm = cfg.rating_filter_abort_encrypted_confirm() if abort else cfg.rating_filter_pause_encrypted_confirm() downvoted = cfg.rating_filter_abort_downvoted() if abort else cfg.rating_filter_pause_downvoted() keywords = cfg.rating_filter_abort_keywords() if abort else cfg.rating_filter_pause_keywords() if (video > 0) and (rating.avg_video > 0) and (rating.avg_video <= video): return T('video') if (audio > 0) and (rating.avg_audio > 0) and (rating.avg_audio <= audio): return T('audio') if (spam and ((rating.avg_spam_cnt > 0) or rating.avg_encrypted_confirm)) or (spam_confirm and rating.avg_spam_confirm): return T('spam') if (encrypted and ((rating.avg_encrypted_cnt > 0) or rating.avg_encrypted_confirm)) or (encrypted_confirm and rating.avg_encrypted_confirm): return T('passworded') if downvoted and (rating.avg_vote_up < rating.avg_vote_down): return T('downvoted') if any(check_keyword(k) for k in keywords.split(',')): return T('keywords') return None def remove_warning_label(msg): """ Standardize errors by removing obsolete "WARNING:" part in all languages """ if ':' in msg: return msg.split(':')[1].strip() return msg SABnzbd-2.3.2/sabnzbd/bpsmeter.py0000644000000000000000000004206413217005257014755 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.bpsmeter - bpsmeter """ import time import logging import re import sabnzbd from sabnzbd.constants import BYTES_FILE_NAME, BYTES_FILE_NAME_OLD, KIBI from sabnzbd.encoding import unicoder import sabnzbd.cfg as cfg DAY = float(24 * 60 * 60) WEEK = DAY * 7 def tomorrow(t): """ Return timestamp for tomorrow (midnight) """ now = time.localtime(t) ntime = (now[0], now[1], now[2], 0, 0, 0, now[6], now[7], now[8]) return time.mktime(ntime) + DAY def this_week(t): """ Return timestamp for start of this week (monday) """ while 1: tm = time.localtime(t) if tm.tm_wday == 0: break t -= DAY monday = (tm.tm_year, tm.tm_mon, tm.tm_mday, 0, 0, 0, 0, 0, tm.tm_isdst) return time.mktime(monday) def next_week(t): """ Return timestamp for start of next week (monday) """ return this_week(t) + WEEK def this_month(t): """ Return timestamp for start of next month """ now = time.localtime(t) ntime = (now[0], now[1], 1, 0, 0, 0, 0, 0, now[8]) return time.mktime(ntime) _DAYS = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) def last_month_day(tm): """ Return last day of this month """ year, month = tm[:2] day = _DAYS[month] # This simple formula for leap years is good enough if day == 28 and (year % 4) == 0: day = 29 return day def next_month(t): """ Return timestamp for start of next month """ now = time.localtime(t) month = now.tm_mon + 1 year = now.tm_year if month > 12: month = 1 year += 1 ntime = (year, month, 1, 0, 0, 0, 0, 0, now[8]) return time.mktime(ntime) def fix_keys(data): """ Convert keys of each dictionary in tuple 'data' to unicode """ new_data = [] if isinstance(data, list): for n in xrange(len(data)): if isinstance(data[n], dict): new = {} for key in data[n]: new[unicoder(key)] = data[n][key] else: new = data[n] new_data.append(new) return new_data class BPSMeter(object): do = None def __init__(self): t = time.time() self.start_time = t self.log_time = t self.speed_log_time = t self.last_update = t self.bps = 0.0 self.bps_list = [] self.bps_list_max = 275 self.day_total = {} self.week_total = {} self.month_total = {} self.grand_total = {} self.timeline_total = {} self.day_label = time.strftime("%Y-%m-%d") self.end_of_day = tomorrow(t) # Time that current day will end self.end_of_week = next_week(t) # Time that current day will end self.end_of_month = next_month(t) # Time that current month will end self.q_day = 1 # Day of quota reset self.q_period = 'm' # Daily/Weekly/Monthly quota = d/w/m self.quota = self.left = 0.0 # Quota and remaining quota self.have_quota = False # Flag for quota active self.q_time = 0L # Next reset time for quota self.q_hour = 0 # Quota reset hour self.q_minute = 0 # Quota reset minute self.quota_enabled = True # Scheduled quota enable/disable BPSMeter.do = self def save(self): """ Save admin to disk """ data = (self.last_update, self.grand_total, self.day_total, self.week_total, self.month_total, self.end_of_day, self.end_of_week, self.end_of_month, self.quota, self.left, self.q_time, self.timeline_total ) sabnzbd.save_admin(data, BYTES_FILE_NAME) def defaults(self): """ Get the latest data from the database and assign to a fake server """ logging.debug('Setting default BPS meter values') history_db = sabnzbd.database.HistoryDB() grand, month, week = history_db.get_history_size() history_db.close() self.grand_total = {} self.month_total = {} self.week_total = {} self.day_total = {} if grand: self.grand_total['x'] = grand if month: self.month_total['x'] = month if week: self.week_total['x'] = week self.quota = self.left = cfg.quota_size.get_float() def read(self): """ Read admin from disk, return True when pause is needed """ res = False quota = self.left = cfg.quota_size.get_float() # Quota for this period self.have_quota = bool(cfg.quota_size()) data = sabnzbd.load_admin(BYTES_FILE_NAME) if not data: data = sabnzbd.load_admin(BYTES_FILE_NAME_OLD) data = fix_keys(data) try: self.last_update, self.grand_total, \ self.day_total, self.week_total, self.month_total, \ self.end_of_day, self.end_of_week, self.end_of_month = data[:8] if len(data) >= 11: self.quota, self.left, self.q_time = data[8:11] logging.debug('Read quota q=%s l=%s reset=%s', self.quota, self.left, self.q_time) if abs(quota - self.quota) > 0.5: self.change_quota() # Get timeline stats if len(data) == 12: self.timeline_total = data[11] else: self.quota = self.left = cfg.quota_size.get_float() res = self.reset_quota() except: self.defaults() # Force update of counters and validate data try: for server in self.grand_total.keys(): self.update(server) except TypeError: self.defaults() self.update() return res def update(self, server=None, amount=0, testtime=None): """ Update counters for "server" with "amount" bytes """ if testtime: t = testtime else: t = time.time() if t > self.end_of_day: # current day passed. get new end of day self.day_label = time.strftime("%Y-%m-%d") self.day_total = {} self.end_of_day = tomorrow(t) - 1.0 if t > self.end_of_week: self.week_total = {} self.end_of_week = next_week(t) - 1.0 if t > self.end_of_month: self.month_total = {} self.end_of_month = next_month(t) - 1.0 if server: if server not in self.day_total: self.day_total[server] = 0L self.day_total[server] += amount if server not in self.week_total: self.week_total[server] = 0L self.week_total[server] += amount if server not in self.month_total: self.month_total[server] = 0L self.month_total[server] += amount if server not in self.grand_total: self.grand_total[server] = 0L self.grand_total[server] += amount if server not in self.timeline_total: self.timeline_total[server] = {} if self.day_label not in self.timeline_total[server]: self.timeline_total[server][self.day_label]= 0L self.timeline_total[server][self.day_label] += amount # Quota check if self.have_quota and self.quota_enabled: self.left -= amount if self.left <= 0.0: if sabnzbd.downloader.Downloader.do and not sabnzbd.downloader.Downloader.do.paused: sabnzbd.downloader.Downloader.do.pause() logging.warning(T('Quota spent, pausing downloading')) # Speedometer try: self.bps = (self.bps * (self.last_update - self.start_time) + amount) / (t - self.start_time) except: self.bps = 0.0 self.last_update = t check_time = t - 5.0 if self.start_time < check_time: self.start_time = check_time if self.bps < 0.01: self.reset() elif self.log_time < check_time: logging.debug("bps: %s", self.bps) self.log_time = t if self.speed_log_time < (t - 1.0): self.add_empty_time() self.bps_list.append(int(self.bps / KIBI)) self.speed_log_time = t def reset(self): t = time.time() self.start_time = t self.log_time = t self.last_update = t self.bps = 0.0 def add_empty_time(self): # Extra zeros, but never more than the maxium! nr_diffs = min(int(time.time() - self.speed_log_time), self.bps_list_max) if nr_diffs > 1: self.bps_list.extend([0] * nr_diffs) # Always trim the list to the max-length if len(self.bps_list) > self.bps_list_max: self.bps_list = self.bps_list[len(self.bps_list) - self.bps_list_max:] def get_sums(self): """ return tuple of grand, month, week, day totals """ return (sum([v for v in self.grand_total.values()]), sum([v for v in self.month_total.values()]), sum([v for v in self.week_total.values()]), sum([v for v in self.day_total.values()]) ) def amounts(self, server): """ Return grand, month, week, day totals for specified server """ return self.grand_total.get(server, 0L), \ self.month_total.get(server, 0L), \ self.week_total.get(server, 0L), \ self.day_total.get(server, 0L), \ self.timeline_total.get(server, {}) def clear_server(self, server): """ Clean counters for specified server """ if server in self.day_total: del self.day_total[server] if server in self.week_total: del self.week_total[server] if server in self.month_total: del self.month_total[server] if server in self.grand_total: del self.grand_total[server] if server in self.timeline_total: del self.timeline_total[server] self.save() def get_bps(self): return self.bps def get_bps_list(self): refresh_rate = int(cfg.refresh_rate()) if cfg.refresh_rate() else 1 self.add_empty_time() # We record every second, but display at the user's refresh-rate return self.bps_list[::refresh_rate] def get_stable_speed(self, timespan=10): """ See if there is a stable speed the last seconds None: indicates it can't determine yet False: the speed was not stable during """ if len(self.bps_list) < timespan: return None # Calculate the variance in the speed avg = sum(self.bps_list[-timespan:]) / timespan vari = 0 for bps in self.bps_list[-timespan:]: vari += abs(bps - avg) vari = vari / timespan try: # See if the variance is less than 5% if (vari / (self.bps / KIBI)) < 0.05: return avg else: return False except: # Probably one of the values was 0 pass return None def reset_quota(self, force=False): """ Check if it's time to reset the quota, optionally resuming Return True, when still paused """ if force or (self.have_quota and time.time() > (self.q_time - 50)): self.quota = self.left = cfg.quota_size.get_float() logging.info('Quota was reset to %s', self.quota) if cfg.quota_resume(): logging.info('Auto-resume due to quota reset') if sabnzbd.downloader.Downloader.do: sabnzbd.downloader.Downloader.do.resume() self.next_reset() return False else: return True def next_reset(self, t=None): """ Determine next reset time """ t = t or time.time() tm = time.localtime(t) if self.q_period == 'd': nx = (tm[0], tm[1], tm[2], self.q_hour, self.q_minute, 0, 0, 0, tm[8]) if (tm.tm_hour * 60 + tm.tm_min) >= (self.q_hour * 60 + self.q_minute): # If today's moment has passed, it will happen tomorrow t = time.mktime(nx) + 24 * 3600 tm = time.localtime(t) elif self.q_period == 'w': if self.q_day < tm.tm_wday + 1 or (self.q_day == tm.tm_wday + 1 and (tm.tm_hour * 60 + tm.tm_min) >= (self.q_hour * 60 + self.q_minute)): tm = time.localtime(next_week(t)) dif = abs(self.q_day - tm.tm_wday - 1) t = time.mktime(tm) + dif * 24 * 3600 tm = time.localtime(t) elif self.q_period == 'm': if self.q_day < tm.tm_mday or (self.q_day == tm.tm_mday and (tm.tm_hour * 60 + tm.tm_min) >= (self.q_hour * 60 + self.q_minute)): tm = time.localtime(next_month(t)) day = min(last_month_day(tm), self.q_day) tm = (tm[0], tm[1], day, self.q_hour, self.q_minute, 0, 0, 0, tm[8]) else: return tm = (tm[0], tm[1], tm[2], self.q_hour, self.q_minute, 0, 0, 0, tm[8]) self.q_time = time.mktime(tm) logging.debug('Will reset quota at %s', tm) def change_quota(self, allow_resume=True): """ Update quota, potentially pausing downloader """ if not self.have_quota and self.quota < 0.5: # Never set, use last period's size per = cfg.quota_period() sums = self.get_sums() if per == 'd': self.left = sums[3] elif per == 'w': self.left = sums[2] elif per == 'm': self.left = sums[1] self.have_quota = bool(cfg.quota_size()) if self.have_quota: quota = cfg.quota_size.get_float() if self.quota: # Quota change, recalculate amount left self.left = quota - (self.quota - self.left) else: # If previously no quota, self.left holds this period's usage self.left = quota - self.left self.quota = quota else: self.quota = self.left = 0L self.update(0) self.next_reset() if self.left > 0.5 and allow_resume: self.resume() # Pattern = # The and part can both be optional __re_day = re.compile(r'^\s*(\d+)[^:]*') __re_hm = re.compile(r'(\d+):(\d+)\s*$') def get_quota(self): """ If quota active, return check-function, hour, minute """ if self.have_quota: self.q_period = cfg.quota_period()[0].lower() self.q_day = 1 self.q_hour = self.q_minute = 0 txt = cfg.quota_day().lower() m = self.__re_day.search(txt) if m: self.q_day = int(m.group(1)) m = self.__re_hm.search(txt) if m: self.q_hour = int(m.group(1)) self.q_minute = int(m.group(2)) if self.q_period == 'w': self.q_day = max(1, self.q_day) self.q_day = min(7, self.q_day) elif self.q_period == 'm': self.q_day = max(1, self.q_day) self.q_day = min(31, self.q_day) else: self.q_day = 1 self.change_quota(allow_resume=False) return quota_handler, self.q_hour, self.q_minute else: return None, 0, 0 def set_status(self, status, action=True): """ Disable/enable quota management """ self.quota_enabled = status if action and not status: self.resume() def resume(self): """ Resume downloading """ if cfg.quota_resume() and sabnzbd.downloader.Downloader.do and sabnzbd.downloader.Downloader.do.paused: sabnzbd.downloader.Downloader.do.resume() def midnight(self): """ Midnight action: dummy update for all servers """ for server in self.day_total.keys(): self.update(server) def quota_handler(): """ To be called from scheduler """ logging.debug('Checking quota') BPSMeter.do.reset_quota() def midnight_action(): if BPSMeter.do: BPSMeter.do.midnight() BPSMeter() SABnzbd-2.3.2/sabnzbd/cfg.py0000644000000000000000000006030513217005257013671 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.cfg - Configuration Parameters """ import re import sabnzbd from sabnzbd.constants import DEF_HOST, DEF_PORT, DEF_STDINTF, DEF_ADMIN_DIR, \ DEF_DOWNLOAD_DIR, DEF_NZBBACK_DIR, DEF_SCANRATE, DEF_COMPLETE_DIR, QUEUE_VERSION from sabnzbd.config import OptionBool, OptionNumber, OptionPassword, \ OptionDir, OptionStr, OptionList, no_nonsense, \ validate_octal, validate_safedir, \ create_api_key, validate_notempty ############################################################################## # Email validation support ############################################################################## RE_VAL = re.compile(r'[^@ ]+@[^.@ ]+\.[^.@ ]') def validate_email(value): global email_endjob, email_full, email_rss if email_endjob() or email_full() or email_rss(): if isinstance(value, list): values = value else: values = [value] for addr in values: if not (addr and RE_VAL.match(addr)): return T('%s is not a valid email address') % addr, None return None, value def validate_server(value): """ Check if server non-empty""" global email_endjob, email_full, email_rss if value == '' and (email_endjob() or email_full() or email_rss()): return T('Server address required'), None else: return None, value if sabnzbd.WIN32: DEF_FOLDER_MAX = 128 else: DEF_FOLDER_MAX = 256 ############################################################################## # Special settings ############################################################################## pre_script = OptionStr('misc', 'pre_script', 'None') queue_complete = OptionStr('misc', 'queue_complete') queue_complete_pers = OptionBool('misc', 'queue_complete_pers', False) bandwidth_perc = OptionNumber('misc', 'bandwidth_perc', 0, 0, 100) refresh_rate = OptionNumber('misc', 'refresh_rate', 0) log_level = OptionNumber('logging', 'log_level', 1, -1, 2) log_size = OptionStr('logging', 'max_log_size', '5242880') log_backups = OptionNumber('logging', 'log_backups', 5, 1, 1024) queue_limit = OptionNumber('misc', 'queue_limit', 20, 0) configlock = OptionBool('misc', 'config_lock', 0) ############################################################################## # One time trackers ############################################################################## converted_nzo_pickles = OptionBool('misc', 'converted_nzo_pickles', False) warned_old_queue = OptionNumber('misc', 'warned_old_queue', QUEUE_VERSION) sched_converted = OptionBool('misc', 'sched_converted', False) notified_new_skin = OptionNumber('misc', 'notified_new_skin', 0) direct_unpack_tested = OptionBool('misc', 'direct_unpack_tested', False) ############################################################################## # Config - General ############################################################################## version_check = OptionNumber('misc', 'check_new_rel', 1) autobrowser = OptionBool('misc', 'auto_browser', True) language = OptionStr('misc', 'language', 'en') enable_https_verification = OptionBool('misc', 'enable_https_verification', True) cherryhost = OptionStr('misc', 'host', DEF_HOST) cherryport = OptionStr('misc', 'port', DEF_PORT) https_port = OptionStr('misc', 'https_port') username = OptionStr('misc', 'username') password = OptionPassword('misc', 'password') bandwidth_max = OptionStr('misc', 'bandwidth_max') cache_limit = OptionStr('misc', 'cache_limit') web_dir = OptionStr('misc', 'web_dir', DEF_STDINTF) web_color = OptionStr('misc', 'web_color', '') https_cert = OptionDir('misc', 'https_cert', 'server.cert', create=False) https_key = OptionDir('misc', 'https_key', 'server.key', create=False) https_chain = OptionDir('misc', 'https_chain', create=False) enable_https = OptionBool('misc', 'enable_https', False) inet_exposure = OptionNumber('misc', 'inet_exposure', 0, protect=True) # 0=local-only, 1=nzb, 2=api, 3=full_api, 4=webui, 5=webui with login for external local_ranges = OptionList('misc', 'local_ranges', protect=True) api_key = OptionStr('misc', 'api_key', create_api_key()) nzb_key = OptionStr('misc', 'nzb_key', create_api_key()) ############################################################################## # Config - Folders ############################################################################## umask = OptionStr('misc', 'permissions', '', validation=validate_octal) download_dir = OptionDir('misc', 'download_dir', DEF_DOWNLOAD_DIR, create=False, validation=validate_safedir) download_free = OptionStr('misc', 'download_free') complete_dir = OptionDir('misc', 'complete_dir', DEF_COMPLETE_DIR, create=False, apply_umask=True, validation=validate_notempty) script_dir = OptionDir('misc', 'script_dir', create=True, writable=False) nzb_backup_dir = OptionDir('misc', 'nzb_backup_dir', DEF_NZBBACK_DIR) admin_dir = OptionDir('misc', 'admin_dir', DEF_ADMIN_DIR, validation=validate_safedir) dirscan_dir = OptionDir('misc', 'dirscan_dir', create=False) dirscan_speed = OptionNumber('misc', 'dirscan_speed', DEF_SCANRATE, 0, 3600) password_file = OptionDir('misc', 'password_file', '', create=False) log_dir = OptionDir('misc', 'log_dir', 'logs', validation=validate_notempty) ############################################################################## # Config - Switches ############################################################################## max_art_tries = OptionNumber('misc', 'max_art_tries', 3, 2) load_balancing = OptionNumber('misc', 'load_balancing', 2) top_only = OptionBool('misc', 'top_only', False) sfv_check = OptionBool('misc', 'sfv_check', True) quick_check_ext_ignore = OptionList('misc', 'quick_check_ext_ignore', ['nfo', 'sfv', 'srr']) script_can_fail = OptionBool('misc', 'script_can_fail', False) ssl_ciphers = OptionStr('misc', 'ssl_ciphers', '') enable_recursive = OptionBool('misc', 'enable_recursive', True) flat_unpack = OptionBool('misc', 'flat_unpack', False) par_option = OptionStr('misc', 'par_option', '', validation=no_nonsense) pre_check = OptionBool('misc', 'pre_check', False) nice = OptionStr('misc', 'nice', '', validation=no_nonsense) ionice = OptionStr('misc', 'ionice', '', validation=no_nonsense) fail_hopeless_jobs = OptionBool('misc', 'fail_hopeless_jobs', True) autodisconnect = OptionBool('misc', 'auto_disconnect', True) no_dupes = OptionNumber('misc', 'no_dupes', 0) no_series_dupes = OptionNumber('misc', 'no_series_dupes', 0) series_propercheck = OptionBool('misc', 'series_propercheck', True) pause_on_pwrar = OptionNumber('misc', 'pause_on_pwrar', 1) ignore_samples = OptionBool('misc', 'ignore_samples', False) auto_sort = OptionBool('misc', 'auto_sort', False) direct_unpack = OptionBool('misc', 'direct_unpack', False) direct_unpack_threads = OptionNumber('misc', 'direct_unpack_threads', 3, 1) propagation_delay = OptionNumber('misc', 'propagation_delay', 0) folder_rename = OptionBool('misc', 'folder_rename', True) replace_spaces = OptionBool('misc', 'replace_spaces', False) replace_dots = OptionBool('misc', 'replace_dots', False) safe_postproc = OptionBool('misc', 'safe_postproc', True) pause_on_post_processing = OptionBool('misc', 'pause_on_post_processing', False) sanitize_safe = OptionBool('misc', 'sanitize_safe', False) cleanup_list = OptionList('misc', 'cleanup_list') unwanted_extensions = OptionList('misc', 'unwanted_extensions') action_on_unwanted_extensions = OptionNumber('misc', 'action_on_unwanted_extensions', 0) new_nzb_on_failure = OptionBool('misc', 'new_nzb_on_failure', False) history_retention = OptionStr('misc', 'history_retention', '0') enable_meta = OptionBool('misc', 'enable_meta', True) quota_size = OptionStr('misc', 'quota_size') quota_day = OptionStr('misc', 'quota_day') quota_resume = OptionBool('misc', 'quota_resume', False) quota_period = OptionStr('misc', 'quota_period', 'm') rating_enable = OptionBool('misc', 'rating_enable', False) rating_host = OptionStr('misc', 'rating_host') rating_api_key = OptionStr('misc', 'rating_api_key') rating_filter_enable = OptionBool('misc', 'rating_filter_enable', False) rating_filter_abort_audio = OptionNumber('misc', 'rating_filter_abort_audio', 0) rating_filter_abort_video = OptionNumber('misc', 'rating_filter_abort_video', 0) rating_filter_abort_encrypted = OptionBool('misc', 'rating_filter_abort_encrypted', False) rating_filter_abort_encrypted_confirm = OptionBool('misc', 'rating_filter_abort_encrypted_confirm', False) rating_filter_abort_spam = OptionBool('misc', 'rating_filter_abort_spam', False) rating_filter_abort_spam_confirm = OptionBool('misc', 'rating_filter_abort_spam_confirm', False) rating_filter_abort_downvoted = OptionBool('misc', 'rating_filter_abort_downvoted', False) rating_filter_abort_keywords = OptionStr('misc', 'rating_filter_abort_keywords') rating_filter_pause_audio = OptionNumber('misc', 'rating_filter_pause_audio', 0) rating_filter_pause_video = OptionNumber('misc', 'rating_filter_pause_video', 0) rating_filter_pause_encrypted = OptionBool('misc', 'rating_filter_pause_encrypted', False) rating_filter_pause_encrypted_confirm = OptionBool('misc', 'rating_filter_pause_encrypted_confirm', False) rating_filter_pause_spam = OptionBool('misc', 'rating_filter_pause_spam', False) rating_filter_pause_spam_confirm = OptionBool('misc', 'rating_filter_pause_spam_confirm', False) rating_filter_pause_downvoted = OptionBool('misc', 'rating_filter_pause_downvoted', False) rating_filter_pause_keywords = OptionStr('misc', 'rating_filter_pause_keywords') ############################################################################## # Config - Sorting ############################################################################## enable_tv_sorting = OptionBool('misc', 'enable_tv_sorting', False) tv_sort_string = OptionStr('misc', 'tv_sort_string') tv_sort_countries = OptionNumber('misc', 'tv_sort_countries', 1) tv_categories = OptionList('misc', 'tv_categories', '') enable_movie_sorting = OptionBool('misc', 'enable_movie_sorting', False) movie_sort_string = OptionStr('misc', 'movie_sort_string') movie_sort_extra = OptionStr('misc', 'movie_sort_extra', '-cd%1', strip=False) movie_extra_folders = OptionBool('misc', 'movie_extra_folder', False) movie_categories = OptionList('misc', 'movie_categories', ['movies']) enable_date_sorting = OptionBool('misc', 'enable_date_sorting', False) date_sort_string = OptionStr('misc', 'date_sort_string') date_categories = OptionList('misc', 'date_categories', ['tv']) ############################################################################## # Config - Scheduling and RSS ############################################################################## schedules = OptionList('misc', 'schedlines') rss_rate = OptionNumber('misc', 'rss_rate', 60, 15, 24 * 60) ############################################################################## # Config - Specials ############################################################################## # Bool switches ampm = OptionBool('misc', 'ampm', False) replace_illegal = OptionBool('misc', 'replace_illegal', True) start_paused = OptionBool('misc', 'start_paused', False) enable_all_par = OptionBool('misc', 'enable_all_par', False) enable_par_cleanup = OptionBool('misc', 'enable_par_cleanup', True) enable_unrar = OptionBool('misc', 'enable_unrar', True) enable_unzip = OptionBool('misc', 'enable_unzip', True) enable_7zip = OptionBool('misc', 'enable_7zip', True) enable_filejoin = OptionBool('misc', 'enable_filejoin', True) enable_tsjoin = OptionBool('misc', 'enable_tsjoin', True) overwrite_files = OptionBool('misc', 'overwrite_files', False) ignore_unrar_dates = OptionBool('misc', 'ignore_unrar_dates', False) ignore_wrong_unrar = OptionBool('misc', 'ignore_wrong_unrar', False) multipar = OptionBool('misc', 'multipar', sabnzbd.WIN32) backup_for_duplicates = OptionBool('misc', 'backup_for_duplicates', True) empty_postproc = OptionBool('misc', 'empty_postproc', False) wait_for_dfolder = OptionBool('misc', 'wait_for_dfolder', False) warn_empty_nzb = OptionBool('misc', 'warn_empty_nzb', True) rss_filenames = OptionBool('misc', 'rss_filenames', False) api_logging = OptionBool('misc', 'api_logging', True) html_login = OptionBool('misc', 'html_login', True) osx_menu = OptionBool('misc', 'osx_menu', True) osx_speed = OptionBool('misc', 'osx_speed', True) warn_dupl_jobs = OptionBool('misc', 'warn_dupl_jobs', True) keep_awake = OptionBool('misc', 'keep_awake', True) win_menu = OptionBool('misc', 'win_menu', True) allow_incomplete_nzb = OptionBool('misc', 'allow_incomplete_nzb', False) enable_bonjour = OptionBool('misc', 'enable_bonjour', True) reject_duplicate_files = OptionBool('misc', 'reject_duplicate_files', False) max_art_opt = OptionBool('misc', 'max_art_opt', False) use_pickle = OptionBool('misc', 'use_pickle', False) ipv6_hosting = OptionBool('misc', 'ipv6_hosting', False) fixed_ports = OptionBool('misc', 'fixed_ports', False) api_warnings = OptionBool('misc', 'api_warnings', True, protect=True) disable_key = OptionBool('misc', 'disable_api_key', False, protect=True) no_penalties = OptionBool('misc', 'no_penalties', False) debug_log_decoding = OptionBool('misc', 'debug_log_decoding', False) # Text values rss_odd_titles = OptionList('misc', 'rss_odd_titles', ['nzbindex.nl/', 'nzbindex.com/', 'nzbclub.com/']) folder_max_length = OptionNumber('misc', 'folder_max_length', DEF_FOLDER_MAX, 20, 65000) req_completion_rate = OptionNumber('misc', 'req_completion_rate', 100.2, 100, 200) selftest_host = OptionStr('misc', 'selftest_host', 'self-test.sabnzbd.org') movie_rename_limit = OptionStr('misc', 'movie_rename_limit', '100M') size_limit = OptionStr('misc', 'size_limit', '0') fsys_type = OptionNumber('misc', 'fsys_type', 0, 0, 2) show_sysload = OptionNumber('misc', 'show_sysload', 2, 0, 2) history_limit = OptionNumber('misc', 'history_limit', 10, 0) wait_ext_drive = OptionNumber('misc', 'wait_ext_drive', 5, 1, 60) marker_file = OptionStr('misc', 'nomedia_marker', '') ipv6_servers = OptionNumber('misc', 'ipv6_servers', 1, 0, 2) url_base = OptionStr('misc', 'url_base', '/sabnzbd') ############################################################################## # Config - Notifications ############################################################################## # [email] email_server = OptionStr('misc', 'email_server', validation=validate_server) email_to = OptionList('misc', 'email_to', validation=validate_email) email_from = OptionStr('misc', 'email_from', validation=validate_email) email_account = OptionStr('misc', 'email_account') email_pwd = OptionPassword('misc', 'email_pwd') email_endjob = OptionNumber('misc', 'email_endjob', 0, 0, 2) email_full = OptionBool('misc', 'email_full', False) email_dir = OptionDir('misc', 'email_dir', create=True) email_rss = OptionBool('misc', 'email_rss', False) email_cats = OptionList('misc', 'email_cats', ['*']) # [ncenter] ncenter_enable = OptionBool('ncenter', 'ncenter_enable', sabnzbd.DARWIN) ncenter_cats = OptionList('ncenter', 'ncenter_cats', ['*']) ncenter_prio_startup = OptionBool('ncenter', 'ncenter_prio_startup', True) ncenter_prio_download = OptionBool('ncenter', 'ncenter_prio_download', False) ncenter_prio_pp = OptionBool('ncenter', 'ncenter_prio_pp', False) ncenter_prio_complete = OptionBool('ncenter', 'ncenter_prio_complete', True) ncenter_prio_failed = OptionBool('ncenter', 'ncenter_prio_failed', True) ncenter_prio_disk_full = OptionBool('ncenter', 'ncenter_prio_disk_full', True) ncenter_prio_new_login = OptionBool('ncenter', 'ncenter_prio_new_login', False) ncenter_prio_warning = OptionBool('ncenter', 'ncenter_prio_warning', False) ncenter_prio_error = OptionBool('ncenter', 'ncenter_prio_error', False) ncenter_prio_queue_done = OptionBool('ncenter', 'ncenter_prio_queue_done', True) ncenter_prio_other = OptionBool('ncenter', 'ncenter_prio_other', False) # [acenter] acenter_enable = OptionBool('acenter', 'acenter_enable', sabnzbd.WIN32) acenter_cats = OptionList('acenter', 'acenter_cats', ['*']) acenter_prio_startup = OptionBool('acenter', 'acenter_prio_startup', False) acenter_prio_download = OptionBool('acenter', 'acenter_prio_download', False) acenter_prio_pp = OptionBool('acenter', 'acenter_prio_pp', False) acenter_prio_complete = OptionBool('acenter', 'acenter_prio_complete', True) acenter_prio_failed = OptionBool('acenter', 'acenter_prio_failed', True) acenter_prio_disk_full = OptionBool('acenter', 'acenter_prio_disk_full', True) acenter_prio_new_login = OptionBool('acenter', 'acenter_prio_new_login', False) acenter_prio_warning = OptionBool('acenter', 'acenter_prio_warning', False) acenter_prio_error = OptionBool('acenter', 'acenter_prio_error', False) acenter_prio_queue_done = OptionBool('acenter', 'acenter_prio_queue_done', True) acenter_prio_other = OptionBool('acenter', 'acenter_prio_other', False) # [ntfosd] ntfosd_enable = OptionBool('ntfosd', 'ntfosd_enable', not sabnzbd.WIN32 and not sabnzbd.DARWIN) ntfosd_cats = OptionList('ntfosd', 'ntfosd_cats', ['*']) ntfosd_prio_startup = OptionBool('ntfosd', 'ntfosd_prio_startup', True) ntfosd_prio_download = OptionBool('ntfosd', 'ntfosd_prio_download', False) ntfosd_prio_pp = OptionBool('ntfosd', 'ntfosd_prio_pp', False) ntfosd_prio_complete = OptionBool('ntfosd', 'ntfosd_prio_complete', True) ntfosd_prio_failed = OptionBool('ntfosd', 'ntfosd_prio_failed', True) ntfosd_prio_disk_full = OptionBool('ntfosd', 'ntfosd_prio_disk_full', True) ntfosd_prio_new_login = OptionBool('ntfosd', 'ntfosd_prio_new_login', False) ntfosd_prio_warning = OptionBool('ntfosd', 'ntfosd_prio_warning', False) ntfosd_prio_error = OptionBool('ntfosd', 'ntfosd_prio_error', False) ntfosd_prio_queue_done = OptionBool('ntfosd', 'ntfosd_prio_queue_done', True) ntfosd_prio_other = OptionBool('ntfosd', 'ntfosd_prio_other', False) # [growl] growl_enable = OptionBool('growl', 'growl_enable', False) growl_cats = OptionList('growl', 'growl_cats', ['*']) growl_server = OptionStr('growl', 'growl_server') growl_password = OptionPassword('growl', 'growl_password') growl_prio_startup = OptionBool('growl', 'growl_prio_startup', True) growl_prio_download = OptionBool('growl', 'growl_prio_download', False) growl_prio_pp = OptionBool('growl', 'growl_prio_pp', False) growl_prio_complete = OptionBool('growl', 'growl_prio_complete', True) growl_prio_failed = OptionBool('growl', 'growl_prio_failed', True) growl_prio_disk_full = OptionBool('growl', 'growl_prio_disk_full', True) growl_prio_new_login = OptionBool('growl', 'growl_prio_new_login', False) growl_prio_warning = OptionBool('growl', 'growl_prio_warning', False) growl_prio_error = OptionBool('growl', 'growl_prio_error', False) growl_prio_queue_done = OptionBool('growl', 'growl_prio_queue_done', True) growl_prio_other = OptionBool('growl', 'growl_prio_other', False) # [prowl] prowl_enable = OptionBool('prowl', 'prowl_enable', False) prowl_cats = OptionList('prowl', 'prowl_cats', ['*']) prowl_apikey = OptionStr('prowl', 'prowl_apikey') prowl_prio_startup = OptionNumber('prowl', 'prowl_prio_startup', -3) prowl_prio_download = OptionNumber('prowl', 'prowl_prio_download', -3) prowl_prio_pp = OptionNumber('prowl', 'prowl_prio_pp', -3) prowl_prio_complete = OptionNumber('prowl', 'prowl_prio_complete', 0) prowl_prio_failed = OptionNumber('prowl', 'prowl_prio_failed', 1) prowl_prio_disk_full = OptionNumber('prowl', 'prowl_prio_disk_full', 1) prowl_prio_new_login = OptionNumber('prowl', 'prowl_prio_new_login', -3) prowl_prio_warning = OptionNumber('prowl', 'prowl_prio_warning', -3) prowl_prio_error = OptionNumber('prowl', 'prowl_prio_error', -3) prowl_prio_queue_done = OptionNumber('prowl', 'prowl_prio_queue_done', 0) prowl_prio_other = OptionNumber('prowl', 'prowl_prio_other', -3) # [pushover] pushover_token = OptionStr('pushover', 'pushover_token') pushover_userkey = OptionStr('pushover', 'pushover_userkey') pushover_device = OptionStr('pushover', 'pushover_device') pushover_emergency_expire = OptionNumber('pushover', 'pushover_emergency_expire', 3600) pushover_emergency_retry = OptionNumber('pushover', 'pushover_emergency_retry', 60) pushover_enable = OptionBool('pushover', 'pushover_enable') pushover_cats = OptionList('pushover', 'pushover_cats', ['*']) pushover_prio_startup = OptionNumber('pushover', 'pushover_prio_startup', -3) pushover_prio_download = OptionNumber('pushover', 'pushover_prio_download', -2) pushover_prio_pp = OptionNumber('pushover', 'pushover_prio_pp', -3) pushover_prio_complete = OptionNumber('pushover', 'pushover_prio_complete', -1) pushover_prio_failed = OptionNumber('pushover', 'pushover_prio_failed', -1) pushover_prio_disk_full = OptionNumber('pushover', 'pushover_prio_disk_full', 1) pushover_prio_new_login = OptionNumber('pushover', 'pushover_prio_new_login', -3) pushover_prio_warning = OptionNumber('pushover', 'pushover_prio_warning', 1) pushover_prio_error = OptionNumber('pushover', 'pushover_prio_error', 1) pushover_prio_queue_done = OptionNumber('pushover', 'pushover_prio_queue_done', -1) pushover_prio_other = OptionNumber('pushover', 'pushover_prio_other', -3) # [pushbullet] pushbullet_enable = OptionBool('pushbullet', 'pushbullet_enable') pushbullet_cats = OptionList('pushbullet', 'pushbullet_cats', ['*']) pushbullet_apikey = OptionStr('pushbullet', 'pushbullet_apikey') pushbullet_device = OptionStr('pushbullet', 'pushbullet_device') pushbullet_prio_startup = OptionNumber('pushbullet', 'pushbullet_prio_startup', 0) pushbullet_prio_download = OptionNumber('pushbullet', 'pushbullet_prio_download', 0) pushbullet_prio_pp = OptionNumber('pushbullet', 'pushbullet_prio_pp', 0) pushbullet_prio_complete = OptionNumber('pushbullet', 'pushbullet_prio_complete', 1) pushbullet_prio_failed = OptionNumber('pushbullet', 'pushbullet_prio_failed', 1) pushbullet_prio_disk_full = OptionNumber('pushbullet', 'pushbullet_prio_disk_full', 1) pushbullet_prio_new_login = OptionNumber('pushbullet', 'pushbullet_prio_new_login', 0) pushbullet_prio_warning = OptionNumber('pushbullet', 'pushbullet_prio_warning', 0) pushbullet_prio_error = OptionNumber('pushbullet', 'pushbullet_prio_error', 0) pushbullet_prio_queue_done = OptionNumber('pushbullet', 'pushbullet_prio_queue_done', 0) pushbullet_prio_other = OptionNumber('pushbullet', 'pushbullet_prio_other', 0) # [nscript] nscript_enable = OptionBool('nscript', 'nscript_enable') nscript_cats = OptionList('nscript', 'nscript_cats', ['*']) nscript_script = OptionStr('nscript', 'nscript_script') nscript_parameters = OptionStr('nscript', 'nscript_parameters') nscript_prio_startup = OptionBool('nscript', 'nscript_prio_startup', True) nscript_prio_download = OptionBool('nscript', 'nscript_prio_download', False) nscript_prio_pp = OptionBool('nscript', 'nscript_prio_pp', False) nscript_prio_complete = OptionBool('nscript', 'nscript_prio_complete', True) nscript_prio_failed = OptionBool('nscript', 'nscript_prio_failed', True) nscript_prio_disk_full = OptionBool('nscript', 'nscript_prio_disk_full', True) nscript_prio_new_login = OptionBool('nscript', 'nscript_prio_new_login', False) nscript_prio_warning = OptionBool('nscript', 'nscript_prio_warning', False) nscript_prio_error = OptionBool('nscript', 'nscript_prio_error', False) nscript_prio_queue_done = OptionBool('nscript', 'nscript_prio_queue_done', True) nscript_prio_other = OptionBool('nscript', 'nscript_prio_other', False) ############################################################################## # Set root folders for Folder config-items ############################################################################## def set_root_folders(home, lcldata): email_dir.set_root(home) download_dir.set_root(home) complete_dir.set_root(home) script_dir.set_root(home) nzb_backup_dir.set_root(lcldata) admin_dir.set_root(lcldata) dirscan_dir.set_root(home) log_dir.set_root(lcldata) password_file.set_root(home) def set_root_folders2(): https_cert.set_root(admin_dir.get_path()) https_key.set_root(admin_dir.get_path()) https_chain.set_root(admin_dir.get_path()) SABnzbd-2.3.2/sabnzbd/config.py0000644000000000000000000010647413217005257014407 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.config - Configuration Support """ import os import re import logging import threading import shutil import time import random from hashlib import md5 from urlparse import urlparse import sabnzbd.misc from sabnzbd.constants import CONFIG_VERSION, NORMAL_PRIORITY, DEFAULT_PRIORITY, MAX_WIN_DFOLDER from sabnzbd.utils import configobj from sabnzbd.decorators import synchronized CONFIG_LOCK = threading.Lock() SAVE_CONFIG_LOCK = threading.Lock() CFG = {} # Holds INI structure # during re-write this variable is global # to allow direct access to INI structure database = {} # Holds the option dictionary modified = False # Signals a change in option dictionary # Should be reset after saving to settings file paramfinder = re.compile(r'''(?:'.*?')|(?:".*?")|(?:[^'",\s][^,]*)''') class Option(object): """ Basic option class, basic fields """ def __init__(self, section, keyword, default_val=None, add=True, protect=False): """ Basic option `section` : single section or comma-separated list of sections a list will be a hierarchy: "foo, bar" --> [foo][[bar]] `keyword` : keyword in the (last) section `default_val` : value returned when no value has been set `callback` : procedure to call when value is successfully changed `protect` : Do not allow setting via the API (specifically set_dict) """ self.__sections = section.split(',') self.__keyword = keyword self.__default_val = default_val self.__value = None self.__callback = None self.__protect = protect # Add myself to the config dictionary if add: global database anchor = database for section in self.__sections: if section not in anchor: anchor[section] = {} anchor = anchor[section] anchor[keyword] = self def __call__(self): """ get() replacement """ return self.get() def get(self): """ Retrieve value field """ if self.__value is not None: return self.__value else: return self.__default_val def get_string(self): return str(self.get()) def get_dict(self, safe=False): """ Return value a dictionary """ return {self.__keyword: self.get()} def set_dict(self, dict): """ Set value based on dictionary """ if self.__protect: return False try: return self.set(dict['value']) except KeyError: return False def __set(self, value): """ Set new value, no validation """ global modified if value is not None: if isinstance(value, list) or isinstance(value, dict) or value != self.__value: self.__value = value modified = True if self.__callback: self.__callback() return None def set(self, value): return self.__set(value) def default(self): return self.__default_val def callback(self, callback): """ Set callback function """ self.__callback = callback def ident(self): """ Return section-list and keyword """ return self.__sections, self.__keyword class OptionNumber(Option): """ Numeric option class, int/float is determined from default value """ def __init__(self, section, keyword, default_val=0, minval=None, maxval=None, validation=None, add=True, protect=False): Option.__init__(self, section, keyword, default_val, add=add, protect=protect) self.__minval = minval self.__maxval = maxval self.__validation = validation self.__int = isinstance(default_val, int) def set(self, value): """ set new value, limited by range """ if value is not None: try: if self.__int: value = int(value) else: value = float(value) except ValueError: value = self._Option__default_val if self.__validation: error, val = self.__validation(value) self._Option__set(val) else: if self.__maxval is not None and value > self.__maxval: value = self.__maxval elif self.__minval is not None and value < self.__minval: value = self.__minval self._Option__set(value) return None class OptionBool(Option): """ Boolean option class """ def __init__(self, section, keyword, default_val=False, add=True, protect=False): Option.__init__(self, section, keyword, int(default_val), add=add, protect=protect) def set(self, value): if value is None: value = 0 try: self._Option__set(int(value)) except ValueError: self._Option__set(0) return None class OptionDir(Option): """ Directory option class """ def __init__(self, section, keyword, default_val='', apply_umask=False, create=True, validation=None, writable=True, add=True): self.__validation = validation self.__root = '' # Base directory for relative paths self.__apply_umask = apply_umask self.__create = create self.__writable = writable Option.__init__(self, section, keyword, default_val, add=add) def get(self): """ Return value, corrected for platform """ if self._Option__value is not None: p = self._Option__value else: p = self._Option__default_val if sabnzbd.WIN32: return p.replace('/', '\\') if '/' in p else p else: return p.replace('\\', '/') if '\\' in p else p def get_path(self): """ Return full absolute path """ value = self.get() path = '' if value: path = sabnzbd.misc.real_path(self.__root, value) if self.__create and not os.path.exists(path): res, path = sabnzbd.misc.create_real_path(self.ident()[1], self.__root, value, self.__apply_umask, self.__writable) return path def test_path(self): """ Return True if path exists """ value = self.get() if value: return os.path.exists(sabnzbd.misc.real_path(self.__root, value)) else: return False def set_root(self, root): """ Set new root, is assumed to be valid """ self.__root = root def set(self, value, create=False): """ Set new dir value, validate and create if needed Return None when directory is accepted Return error-string when not accepted, value will not be changed 'create' means try to create (but don't set permanent create flag) """ error = None if value is not None and (create or value != self.get()): value = value.strip() if self.__validation: error, value = self.__validation(self.__root, value, self._Option__default_val) if not error: if value and (self.__create or create): res, path = sabnzbd.misc.create_real_path(self.ident()[1], self.__root, value, self.__apply_umask, self.__writable) if not res: error = T('Cannot create %s folder %s') % (self.ident()[1], path) if not error: self._Option__set(value) return error def set_create(self, value): """ Set auto-creation value """ self.__create = value class OptionList(Option): """ List option class """ def __init__(self, section, keyword, default_val=None, validation=None, add=True, protect=False): self.__validation = validation if default_val is None: default_val = [] Option.__init__(self, section, keyword, default_val, add=add, protect=protect) def set(self, value): """ Set the list given a comma-separated string or a list """ error = None if value is not None: if not isinstance(value, list): if '"' not in value and ',' not in value: value = value.split() else: value = paramfinder.findall(value) if self.__validation: error, value = self.__validation(value) if not error: self._Option__set(value) return error def get_string(self): """ Return the list as a comma-separated string """ lst = self.get() if isinstance(lst, basestring): return lst else: return ', '.join(lst) def default_string(self): """ Return the default list as a comma-separated string """ lst = self.default() if isinstance(lst, basestring): return lst else: return ', '.join(lst) class OptionStr(Option): """ String class """ def __init__(self, section, keyword, default_val='', validation=None, add=True, strip=True, protect=False): Option.__init__(self, section, keyword, default_val, add=add, protect=protect) self.__validation = validation self.__strip = strip def get_float(self): """ Return value converted to a float, allowing KMGT notation """ return sabnzbd.misc.from_units(self.get()) def get_int(self): """ Return value converted to an int, allowing KMGT notation """ return int(self.get_float()) def set(self, value): """ Set stripped value """ error = None if isinstance(value, basestring) and self.__strip: value = value.strip() if self.__validation: error, val = self.__validation(value) self._Option__set(val) else: self._Option__set(value) return error class OptionPassword(Option): """ Password class """ def __init__(self, section, keyword, default_val='', add=True): Option.__init__(self, section, keyword, default_val, add=add) self.get_string = self.get_stars def get(self): """ Return decoded password """ value = self._Option__value if value is None: return self._Option__default_val else: return decode_password(value, self.ident()) def get_stars(self): """ Return decoded password as asterisk string """ return '*' * len(decode_password(self.get(), self.ident())) def get_dict(self, safe=False): """ Return value a dictionary """ if safe: return {self._Option__keyword: self.get_stars()} else: return {self._Option__keyword: self.get()} def set(self, pw): """ Set password, encode it """ if (pw is not None and pw == '') or (pw and pw.strip('*')): self._Option__set(encode_password(pw)) return None @synchronized(CONFIG_LOCK) def add_to_database(section, keyword, obj): """ add object as section/keyword to INI database """ global database if section not in database: database[section] = {} database[section][keyword] = obj @synchronized(CONFIG_LOCK) def delete_from_database(section, keyword): """ Remove section/keyword from INI database """ global database, CFG, modified del database[section][keyword] if section == 'servers' and '[' in keyword: keyword = keyword.replace('[', '{').replace(']', '}') try: del CFG[section][keyword] except KeyError: pass modified = True class ConfigServer(object): """ Class defining a single server """ def __init__(self, name, values): self.__name = name name = 'servers,' + self.__name self.displayname = OptionStr(name, 'displayname', '', add=False) self.host = OptionStr(name, 'host', '', add=False) self.port = OptionNumber(name, 'port', 119, 0, 2 ** 16 - 1, add=False) self.timeout = OptionNumber(name, 'timeout', 60, 20, 240, add=False) self.username = OptionStr(name, 'username', '', add=False) self.password = OptionPassword(name, 'password', '', add=False) self.connections = OptionNumber(name, 'connections', 1, 0, 100, add=False) self.ssl = OptionBool(name, 'ssl', False, add=False) self.ssl_verify = OptionNumber(name, 'ssl_verify', 2, add=False) # 0=No, 1=Normal, 2=Strict (hostname verification) self.enable = OptionBool(name, 'enable', True, add=False) self.optional = OptionBool(name, 'optional', False, add=False) self.retention = OptionNumber(name, 'retention', add=False) self.send_group = OptionBool(name, 'send_group', False, add=False) self.priority = OptionNumber(name, 'priority', 0, 0, 99, add=False) # 'fillserver' field only here in order to set a proper priority when converting self.fillserver = OptionBool(name, 'fillserver', False, add=False) self.notes = OptionStr(name, 'notes', '', add=False) self.set_dict(values) add_to_database('servers', self.__name, self) def set_dict(self, values): """ Set one or more fields, passed as dictionary """ for kw in ('displayname', 'host', 'port', 'timeout', 'username', 'password', 'connections', 'fillserver', 'ssl', 'ssl_verify', 'send_group', 'enable', 'optional', 'retention', 'priority', 'notes'): try: value = values[kw] except KeyError: continue exec 'self.%s.set(value)' % kw if not self.displayname(): self.displayname.set(self.__name) return True def get_dict(self, safe=False): """ Return a dictionary with all attributes """ dict = {} dict['name'] = self.__name dict['displayname'] = self.displayname() dict['host'] = self.host() dict['port'] = self.port() dict['timeout'] = self.timeout() dict['username'] = self.username() if safe: dict['password'] = self.password.get_stars() else: dict['password'] = self.password() dict['connections'] = self.connections() dict['ssl'] = self.ssl() dict['ssl_verify'] = self.ssl_verify() dict['enable'] = self.enable() dict['optional'] = self.optional() dict['retention'] = self.retention() dict['send_group'] = self.send_group() dict['priority'] = self.priority() dict['notes'] = self.notes() return dict def delete(self): """ Remove from database """ delete_from_database('servers', self.__name) def rename(self, name): """ Give server new display name """ self.displayname.set(name) def ident(self): return 'servers', self.__name class ConfigCat(object): """ Class defining a single category """ def __init__(self, name, values): self.__name = name name = 'categories,' + name self.order = OptionNumber(name, 'order', 0, 0, 100, add=False) self.pp = OptionStr(name, 'pp', '', add=False) self.script = OptionStr(name, 'script', 'Default', add=False) self.dir = OptionDir(name, 'dir', add=False, create=False) self.newzbin = OptionList(name, 'newzbin', add=False) self.priority = OptionNumber(name, 'priority', DEFAULT_PRIORITY, add=False) self.set_dict(values) add_to_database('categories', self.__name, self) def set_dict(self, values): """ Set one or more fields, passed as dictionary """ for kw in ('order', 'pp', 'script', 'dir', 'newzbin', 'priority'): try: value = values[kw] except KeyError: continue exec 'self.%s.set(value)' % kw return True def get_dict(self, safe=False): """ Return a dictionary with all attributes """ dict = {} dict['name'] = self.__name dict['order'] = self.order() dict['pp'] = self.pp() dict['script'] = self.script() dict['dir'] = self.dir() dict['newzbin'] = self.newzbin.get_string() dict['priority'] = self.priority() return dict def delete(self): """ Remove from database """ delete_from_database('categories', self.__name) class OptionFilters(Option): """ Filter list class """ def __init__(self, section, keyword, add=True): Option.__init__(self, section, keyword, add=add) self.set([]) def move(self, current, new): """ Move filter from position 'current' to 'new' """ lst = self.get() try: item = lst.pop(current) lst.insert(new, item) except IndexError: return self.set(lst) def update(self, pos, value): """ Update filter 'pos' definition, value is a list Append if 'pos' outside list """ lst = self.get() try: lst[pos] = value except IndexError: lst.append(value) self.set(lst) def delete(self, pos): """ Remove filter 'pos' """ lst = self.get() try: lst.pop(pos) except IndexError: return self.set(lst) def get_dict(self, safe=False): """ Return filter list as a dictionary with keys 'filter[0-9]+' """ dict = {} n = 0 for filter in self.get(): dict['filter' + str(n)] = filter n = n + 1 return dict def set_dict(self, values): """ Create filter list from dictionary with keys 'filter[0-9]+' """ filters = [] for n in xrange(len(values)): kw = 'filter%d' % n val = values.get(kw) if val is not None: val = values[kw] if isinstance(val, list): filters.append(val) else: filters.append(paramfinder.findall(val)) while len(filters[-1]) < 7: filters[-1].append('1') if not filters[-1][6]: filters[-1][6] = '1' if filters: self.set(filters) return True class ConfigRSS(object): """ Class defining a single Feed definition """ def __init__(self, name, values): self.__name = name name = 'rss,' + name self.uri = OptionList(name, 'uri', add=False) self.cat = OptionStr(name, 'cat', add=False) self.pp = OptionStr(name, 'pp', '', add=False) self.script = OptionStr(name, 'script', add=False) self.enable = OptionBool(name, 'enable', add=False) self.priority = OptionNumber(name, 'priority', DEFAULT_PRIORITY, DEFAULT_PRIORITY, 2, add=False) self.filters = OptionFilters(name, 'filters', add=False) self.filters.set([['', '', '', 'A', '*', DEFAULT_PRIORITY, '1']]) self.set_dict(values) add_to_database('rss', self.__name, self) def set_dict(self, values): """ Set one or more fields, passed as dictionary """ for kw in ('uri', 'cat', 'pp', 'script', 'priority', 'enable'): try: value = values[kw] except KeyError: continue exec 'self.%s.set(value)' % kw self.filters.set_dict(values) return True def get_dict(self, safe=False): """ Return a dictionary with all attributes """ dict = {} dict['name'] = self.__name dict['uri'] = self.uri() dict['cat'] = self.cat() dict['pp'] = self.pp() dict['script'] = self.script() dict['enable'] = self.enable() dict['priority'] = self.priority() filters = self.filters.get_dict() for kw in filters: dict[kw] = filters[kw] return dict def delete(self): """ Remove from database """ delete_from_database('rss', self.__name) def ident(self): return 'rss', self.__name def get_dconfig(section, keyword, nested=False): """ Return a config values dictionary, Single item or slices based on 'section', 'keyword' """ data = {} if not section: for section in database.keys(): res, conf = get_dconfig(section, None, True) data.update(conf) elif not keyword: try: sect = database[section] except KeyError: return False, {} if section in ('servers', 'categories', 'rss'): data[section] = [] for keyword in sect.keys(): res, conf = get_dconfig(section, keyword, True) data[section].append(conf) else: data[section] = {} for keyword in sect.keys(): res, conf = get_dconfig(section, keyword, True) data[section].update(conf) else: try: item = database[section][keyword] except KeyError: return False, {} data = item.get_dict(safe=True) if not nested: if section in ('servers', 'categories', 'rss'): data = {section: [data]} else: data = {section: data} return True, data def get_config(section, keyword): """ Return a config object, based on 'section', 'keyword' """ try: return database[section][keyword] except KeyError: logging.debug('Missing configuration item %s,%s', section, keyword) return None def set_config(kwargs): """ Set a config item, using values in dictionary """ try: item = database[kwargs.get('section')][kwargs.get('keyword')] except KeyError: return False item.set_dict(kwargs) return True def delete(section, keyword): """ Delete specific config item """ try: database[section][keyword].delete() except KeyError: return ############################################################################## # INI file support # # This does input and output of configuration to an INI file. # It translates this data structure to the config database. ############################################################################## @synchronized(SAVE_CONFIG_LOCK) def read_config(path): """ Read the complete INI file and check its version number if OK, pass values to config-database """ return _read_config(path) def _read_config(path, try_backup=False): """ Read the complete INI file and check its version number if OK, pass values to config-database """ global CFG, database, modified if try_backup or not os.path.exists(path): # Not found, try backup try: shutil.copyfile(path + '.bak', path) try_backup = True except IOError: pass if not os.path.exists(path): # No file found, create default INI file try: if not sabnzbd.WIN32: prev = os.umask(077) fp = open(path, "w") fp.write("__version__=%s\n[misc]\n[logging]\n" % CONFIG_VERSION) fp.close() if not sabnzbd.WIN32: os.umask(prev) except IOError: return False, 'Cannot create INI file %s' % path try: fp = open(path, 'rb') lines = fp.read().split('\n') if len(lines) == 1: fp.seek(0) lines = fp.read().split('\r') lines = [line.rstrip('\r\n') for line in lines] fp.close() try: # First try UTF-8 encoding CFG = configobj.ConfigObj(lines, default_encoding='utf-8', encoding='utf-8') except UnicodeDecodeError: # Failed, enable retry CFG = {} if not re.search(r'utf[ -]*8', CFG.get('__encoding__', ''), re.I): # INI file is still in 8bit ASCII encoding, so try Latin-1 instead CFG = configobj.ConfigObj(lines, default_encoding='cp1252', encoding='cp1252') except (IOError, configobj.ConfigObjError, UnicodeEncodeError), strerror: if try_backup: if isinstance(strerror, UnicodeEncodeError): strerror = 'Character encoding of the file is inconsistent' return False, '"%s" is not a valid configuration file
Error message: %s' % (path, strerror) else: # Try backup file return _read_config(path, True) try: version = sabnzbd.misc.int_conv(CFG['__version__']) if version > int(CONFIG_VERSION): return False, "Incorrect version number %s in %s" % (version, path) except (KeyError, ValueError): pass CFG.filename = path CFG.encoding = 'utf-8' CFG['__encoding__'] = u'utf-8' CFG['__version__'] = unicode(CONFIG_VERSION) # Use CFG data to set values for all static options for section in database: if section not in ('servers', 'categories', 'rss'): for option in database[section]: sec, kw = database[section][option].ident() sec = sec[-1] try: database[section][option].set(CFG[sec][kw]) except KeyError: pass define_categories() define_rss() define_servers() modified = False return True, "" @synchronized(SAVE_CONFIG_LOCK) def save_config(force=False): """ Update Setup file with current option values """ global CFG, database, modified if not (modified or force): return True for section in database: if section in ('servers', 'categories', 'rss'): try: CFG[section] except KeyError: CFG[section] = {} for subsec in database[section]: if section == 'servers': subsec_mod = subsec.replace('[', '{').replace(']', '}') else: subsec_mod = subsec try: CFG[section][subsec_mod] except KeyError: CFG[section][subsec_mod] = {} items = database[section][subsec].get_dict() CFG[section][subsec_mod] = items else: for option in database[section]: sec, kw = database[section][option].ident() sec = sec[-1] try: CFG[sec] except KeyError: CFG[sec] = {} value = database[section][option]() # bool is a subclass of int, check first if isinstance(value, bool): # convert bool to int when saving so we store 0 or 1 CFG[sec][kw] = str(int(value)) elif isinstance(value, int): CFG[sec][kw] = str(value) else: CFG[sec][kw] = value res = False filename = CFG.filename bakname = filename + '.bak' # Check if file is writable if not sabnzbd.misc.is_writable(filename): logging.error(T('Cannot write to INI file %s'), filename) return res # copy current file to backup try: shutil.copyfile(filename, bakname) shutil.copymode(filename, bakname) except: # Something wrong with the backup, logging.error(T('Cannot create backup file for %s'), bakname) logging.info("Traceback: ", exc_info=True) return res # Write new config file try: logging.info('Writing settings to INI file %s', filename) CFG.write() shutil.copymode(bakname, filename) modified = False res = True except: logging.error(T('Cannot write to INI file %s'), filename) logging.info("Traceback: ", exc_info=True) try: sabnzbd.misc.remove_file(filename) except: pass # Restore INI file from backup sabnzbd.misc.renamer(bakname, filename) return res def define_servers(): """ Define servers listed in the Setup file return a list of ConfigServer instances """ global CFG try: for server in CFG['servers']: svr = CFG['servers'][server] s = ConfigServer(server.replace('{', '[').replace('}', ']'), svr) if s.fillserver(): # One time conversion of backup to priority 1 s.priority.set(1) s.fillserver.set(False) except KeyError: pass def get_servers(): global database try: return database['servers'] except KeyError: return {} def define_categories(force=False): """ Define categories listed in the Setup file return a list of ConfigCat instances """ global CFG, categories try: for cat in CFG['categories']: ConfigCat(cat, CFG['categories'][cat]) except KeyError: pass def old_def(item, default): """ Get old INI setting from [misc], if missing use 'default' """ try: return CFG['misc'][item] except KeyError: return default def get_categories(cat=0): """ Return link to categories section. This section will always contain special category '*' When 'cat' is given, a link to that category or to '*' is returned """ global database if 'categories' not in database: database['categories'] = {} cats = database['categories'] # Add Default categories if '*' not in cats: ConfigCat('*', {'pp': old_def('dirscan_opts', '3'), 'script': old_def('dirscan_script', 'None'), 'priority': old_def('dirscan_priority', NORMAL_PRIORITY)}) # Add some category suggestions ConfigCat('movies', {}) ConfigCat('tv', {}) ConfigCat('audio', {}) ConfigCat('software', {}) # Save config for future use save_config(True) if not isinstance(cat, int): try: cats = cats[cat] except KeyError: cats = cats['*'] return cats def get_ordered_categories(): """ Return list-copy of categories section that's ordered by user's ordering including Default-category """ database_cats = get_categories() # Transform to list and sort categories = [] for cat in database_cats.keys(): if cat != '*': categories.append(database_cats[cat].get_dict()) # Sort and add default * category categories.sort(key=lambda cat: cat['order']) categories.insert(0, database_cats['*'].get_dict()) return categories def define_rss(): """ Define rss-feeds listed in the Setup file return a list of ConfigRSS instances """ global CFG try: for r in CFG['rss']: ConfigRSS(r, CFG['rss'][r]) except KeyError: pass def get_rss(): global database try: # We have to remove non-seperator commas by detecting if they are valid URL's for feed_key in database['rss']: feed = database['rss'][feed_key] # Only modify if we have to, to prevent repeated config-saving have_new_uri = False # Create a new corrected list new_feed_uris = [] for feed_uri in feed.uri(): if new_feed_uris and not urlparse(feed_uri).scheme and urlparse(new_feed_uris[-1]).scheme: # Current one has no scheme but previous one does, append to previous new_feed_uris[-1] += '%2C' + feed_uri have_new_uri = True continue # Add full working URL new_feed_uris.append(feed_uri) # Set new list if have_new_uri: feed.uri.set(new_feed_uris) return database['rss'] except KeyError: return {} def get_filename(): global CFG return CFG.filename ############################################################################## # Default Validation handlers ############################################################################## __PW_PREFIX = '!!!encoded!!!' def encode_password(pw): """ Encode password in hexadecimal if needed """ enc = False if pw: encPW = __PW_PREFIX for c in pw: cnum = ord(c) if c == '#' or cnum < 33 or cnum > 126: enc = True encPW += '%2x' % cnum if enc: return encPW return pw def decode_password(pw, name): """ Decode hexadecimal encoded password but only decode when prefixed """ decPW = '' if pw and pw.startswith(__PW_PREFIX): for n in range(len(__PW_PREFIX), len(pw), 2): try: ch = chr(int(pw[n] + pw[n + 1], 16)) except ValueError: logging.error(T('Incorrectly encoded password %s'), name) return '' decPW += ch return decPW else: return pw def no_nonsense(value): """ Strip and Filter out None and 'None' from strings """ value = str(value).strip() if value.lower() == 'none': value = '' return None, value def validate_octal(value): """ Check if string is valid octal number """ if not value: return None, value try: int(value, 8) return None, value except: return T('%s is not a correct octal value') % value, None def validate_no_unc(root, value, default): """ Check if path isn't a UNC path """ # Only need to check the 'value' part if value and not value.startswith(r'\\'): return validate_notempty(root, value, default) else: return T('UNC path "%s" not allowed here') % value, None def validate_safedir(root, value, default): """ Allow only when queues are empty and no UNC On Windows path should be small """ if sabnzbd.WIN32 and value and len(sabnzbd.misc.real_path(root, value)) >= MAX_WIN_DFOLDER: return T('Error: Path length should be below %s.') % MAX_WIN_DFOLDER, None if sabnzbd.empty_queues(): return validate_no_unc(root, value, default) else: return T('Error: Queue not empty, cannot change folder.'), None def validate_notempty(root, value, default): """ If value is empty, return default """ if value: return None, value else: return None, default def create_api_key(): """ Return a new randomized API_KEY """ # Create some values to seed md5 t = str(time.time()) r = str(random.random()) # Create the md5 instance and give it the current time m = md5(t) # Update the md5 instance with the random variable m.update(r) # Return a hex digest of the md5, eg 49f68a5c8493ec2c0bf489821c21fc3b return m.hexdigest() SABnzbd-2.3.2/sabnzbd/constants.py0000644000000000000000000001233213217005257015143 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. from collections import namedtuple from re import compile CONFIG_VERSION = 19 QUEUE_VERSION = 10 POSTPROC_QUEUE_VERSION = 2 REC_RAR_VERSION = 500 PNFO = namedtuple('PNFO', 'repair unpack delete script nzo_id filename password unpackstrht ' 'msgid category url bytes_left bytes avg_stamp avg_date finished_files ' 'active_files queued_files status priority bytes_missing direct_unpack') QNFO = namedtuple('QNFO', 'bytes bytes_left bytes_left_previous_page list q_size_list q_fullsize') ANFO = namedtuple('ANFO', 'article_sum cache_size cache_limit') GIGI = float(2 ** 30) MEBI = float(2 ** 20) KIBI = float(2 ** 10) BYTES_FILE_NAME_OLD = 'totals9.sab' BYTES_FILE_NAME = 'totals10.sab' QUEUE_FILE_TMPL = 'queue%s.sab' QUEUE_FILE_NAME = QUEUE_FILE_TMPL % QUEUE_VERSION POSTPROC_QUEUE_FILE_NAME = 'postproc%s.sab' % POSTPROC_QUEUE_VERSION RSS_FILE_NAME = 'rss_data.sab' SCAN_FILE_NAME = 'watched_data2.sab' FUTURE_Q_FOLDER = 'future' JOB_ADMIN = '__ADMIN__' VERIFIED_FILE = '__verified__' RENAMES_FILE = '__renames__' ATTRIB_FILE = 'SABnzbd_attrib' REPAIR_REQUEST = 'repair-all.sab' SABYENC_VERSION_REQUIRED = '3.3.2' DB_HISTORY_VERSION = 1 DB_HISTORY_NAME = 'history%s.db' % DB_HISTORY_VERSION DEF_DOWNLOAD_DIR = 'Downloads/incomplete' DEF_COMPLETE_DIR = 'Downloads/complete' DEF_ADMIN_DIR = 'admin' DEF_NZBBACK_DIR = '' DEF_LANGUAGE = 'locale' DEF_INTERFACES = 'interfaces' DEF_EMAIL_TMPL = 'email' DEF_STDCONFIG = 'Config' DEF_STDINTF = 'Glitter' DEF_SKIN_COLORS = {'smpl': 'white', 'Glitter': 'Default', 'plush': 'gold'} DEF_MAIN_TMPL = 'templates/main.tmpl' DEF_INI_FILE = 'sabnzbd.ini' DEF_HOST = '127.0.0.1' DEF_PORT = 8080 DEF_WORKDIR = 'sabnzbd' DEF_LOG_FILE = 'sabnzbd.log' DEF_LOG_ERRFILE = 'sabnzbd.error.log' DEF_LOG_CHERRY = 'cherrypy.log' DEF_ARTICLE_CACHE_DEFAULT = '500M' DEF_ARTICLE_CACHE_MAX = '1G' DEF_TIMEOUT = 60 DEF_SCANRATE = 5 MAX_URL_RETRIES = 10 MAX_DECODE_QUEUE = 10 LIMIT_DECODE_QUEUE = 100 MAX_WARNINGS = 20 MAX_WIN_DFOLDER = 60 MAX_BAD_ARTICLES = 5 REPAIR_PRIORITY = 3 TOP_PRIORITY = 2 HIGH_PRIORITY = 1 NORMAL_PRIORITY = 0 LOW_PRIORITY = -1 DEFAULT_PRIORITY = -100 PAUSED_PRIORITY = -2 DUP_PRIORITY = -3 STOP_PRIORITY = -4 STAGES = {'Source': 0, 'Download': 1, 'Servers': 2, 'Repair': 3, 'Filejoin': 4, 'Unpack': 5, 'Script': 6} VALID_ARCHIVES = ('.zip', '.rar', '.7z') IGNORED_FOLDERS = ('@eaDir', '.appleDouble') # (MATCHER, [EXTRA, MATCHERS]) series_match = [(compile(r'( [sS]|[\d]+)x(\d+)'), # 1x01 [compile(r'^[-\.]+([sS]|[\d])+x(\d+)'), compile(r'^[-\.](\d+)')]), (compile(r'[Ss](\d+)[\.\-]?[Ee](\d+)'), # S01E01 [compile(r'^[-\.]+[Ss](\d+)[\.\-]?[Ee](\d+)'), compile(r'^[-\.](\d+)')]), (compile(r'[ \-_\.](\d)(\d{2,2})[ \-_\.]'), # .101. / _101_ / etc. []), (compile(r'[ \-_\.](\d)(\d{2,2})$'), # .101 at end of title []) ] date_match = [r'(\d{4})\W(\d{1,2})\W(\d{1,2})', # 2008-10-16 r'(\d{1,2})\W(\d{1,2})\W(\d{4})'] # 10.16.2008 year_match = r'[\W]([1|2]\d{3})([^\w]|$)' # Something '(YYYY)' or '.YYYY.' or ' YYYY ' sample_match = r'((^|[\W_])(sample|proof))' # something-sample or something-proof class Status(): COMPLETED = 'Completed' # PP: Job is finished CHECKING = 'Checking' # Q: Pre-check is running DOWNLOADING = 'Downloading' # Q: Normal downloading EXTRACTING = 'Extracting' # PP: Archives are being extracted FAILED = 'Failed' # PP: Job has failed, now in History FETCHING = 'Fetching' # Q: Job is downloading extra par2 files GRABBING = 'Grabbing' # Q: Getting an NZB from an external site MOVING = 'Moving' # PP: Files are being moved PAUSED = 'Paused' # Q: Job is paused QUEUED = 'Queued' # Q: Job is waiting for its turn to download QUICK_CHECK = 'QuickCheck' # PP: QuickCheck verification is running REPAIRING = 'Repairing' # PP: Job is being repaired (by par2) RUNNING = 'Running' # PP: User's post processing script is running VERIFYING = 'Verifying' # PP: Job is being verified (by par2) DELETED = 'Deleted' # Q: Job has been deleted (and is almost gone) PROP = 'Propagating' # Q: Delayed download NOTIFY_KEYS = ('startup', 'download', 'pp', 'complete', 'failed', 'queue_done', 'disk_full', 'new_login', 'warning', 'error', 'other') SABnzbd-2.3.2/sabnzbd/database.py0000644000000000000000000005230013217005257014672 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.database - Database Support """ try: import sqlite3 except: try: import pysqlite2.dbapi2 as sqlite3 except: pass import os import time import zlib import logging import sys import threading import sabnzbd import sabnzbd.cfg from sabnzbd.constants import DB_HISTORY_NAME, STAGES from sabnzbd.encoding import unicoder from sabnzbd.bpsmeter import this_week, this_month from sabnzbd.decorators import synchronized from sabnzbd.misc import get_all_passwords, int_conv, remove_file, caller_name DB_LOCK = threading.RLock() def convert_search(search): """ Convert classic wildcard to SQL wildcard """ if not search: # Default value search = '' else: # Allow * for wildcard matching and space search = search.replace('*', '%').replace(' ', '%') # Allow ^ for start of string and $ for end of string if search and search.startswith('^'): search = search.replace('^', '') search += '%' elif search and search.endswith('$'): search = search.replace('$', '') search = '%' + search else: search = '%' + search + '%' return search class HistoryDB(object): """ Class to access the History database Each class-instance will create an access channel that can be used in one thread. Each thread needs its own class-instance! """ # These class attributes will be accessed directly because # they need to be shared by all instances db_path = None # Will contain full path to history database done_cleaning = False # Ensure we only do one Vacuum per session @synchronized(DB_LOCK) def __init__(self): """ Determine databse path and create connection """ self.con = self.c = None if not HistoryDB.db_path: HistoryDB.db_path = os.path.join(sabnzbd.cfg.admin_dir.get_path(), DB_HISTORY_NAME) self.connect() def connect(self): """ Create a connection to the database """ create_table = not os.path.exists(HistoryDB.db_path) self.con = sqlite3.connect(HistoryDB.db_path) self.con.row_factory = dict_factory self.c = self.con.cursor() if create_table: self.create_history_db() elif not HistoryDB.done_cleaning: # Run VACUUM on sqlite # When an object (table, index, or trigger) is dropped from the database, it leaves behind empty space # http://www.sqlite.org/lang_vacuum.html HistoryDB.done_cleaning = True self.execute('VACUUM') self.execute('PRAGMA user_version;') try: version = self.c.fetchone()['user_version'] except TypeError: version = 0 if version < 1: # Add any missing columns added since first DB version # Use "and" to stop when database has been reset due to corruption _ = self.execute('PRAGMA user_version = 1;') and \ self.execute('ALTER TABLE "history" ADD COLUMN series TEXT;') and \ self.execute('ALTER TABLE "history" ADD COLUMN md5sum TEXT;') if version < 2: # Add any missing columns added since second DB version # Use "and" to stop when database has been reset due to corruption _ = self.execute('PRAGMA user_version = 2;') and \ self.execute('ALTER TABLE "history" ADD COLUMN password TEXT;') def execute(self, command, args=(), save=False): ''' Wrapper for executing SQL commands ''' for tries in xrange(5, 0, -1): try: if args and isinstance(args, tuple): self.c.execute(command, args) else: self.c.execute(command) if save: self.con.commit() return True except: error = str(sys.exc_value) if tries >= 0 and 'is locked' in error: logging.debug('Database locked, wait and retry') time.sleep(0.5) continue elif 'readonly' in error: logging.error(T('Cannot write to History database, check access rights!')) # Report back success, because there's no recovery possible return True elif 'not a database' in error or 'malformed' in error or 'duplicate column name' in error: logging.error(T('Damaged History database, created empty replacement')) logging.info("Traceback: ", exc_info=True) self.close() try: remove_file(HistoryDB.db_path) except: pass self.connect() # Return False in case of "duplicate column" error # because the column addition in connect() must be terminated return 'duplicate column name' not in error else: logging.error(T('SQL Command Failed, see log')) logging.info("SQL: %s", command) logging.info("Arguments: %s", repr(args)) logging.info("Traceback: ", exc_info=True) try: self.con.rollback() except: logging.debug("Rollback Failed:", exc_info=True) return False def create_history_db(self): """ Create a new (empty) database file """ self.execute(""" CREATE TABLE "history" ( "id" INTEGER PRIMARY KEY, "completed" INTEGER NOT NULL, "name" TEXT NOT NULL, "nzb_name" TEXT NOT NULL, "category" TEXT, "pp" TEXT, "script" TEXT, "report" TEXT, "url" TEXT, "status" TEXT, "nzo_id" TEXT, "storage" TEXT, "path" TEXT, "script_log" BLOB, "script_line" TEXT, "download_time" INTEGER, "postproc_time" INTEGER, "stage_log" TEXT, "downloaded" INTEGER, "completeness" INTEGER, "fail_message" TEXT, "url_info" TEXT, "bytes" INTEGER, "meta" TEXT, "series" TEXT, "md5sum" TEXT, "password" TEXT ) """) self.execute('PRAGMA user_version = 2;') def close(self): """ Close database connection """ try: self.c.close() self.con.close() except: logging.error(T('Failed to close database, see log')) logging.info("Traceback: ", exc_info=True) def remove_completed(self, search=None): """ Remove all completed jobs from the database, optional with `search` pattern """ search = convert_search(search) logging.info('Removing all completed jobs from history') return self.execute("""DELETE FROM history WHERE name LIKE ? AND status = 'Completed'""", (search,), save=True) def get_failed_paths(self, search=None): """ Return list of all storage paths of failed jobs (may contain non-existing or empty paths) """ search = convert_search(search) fetch_ok = self.execute("""SELECT path FROM history WHERE name LIKE ? AND status = 'Failed'""", (search,)) if fetch_ok: return [item.get('path') for item in self.c.fetchall()] else: return [] def remove_failed(self, search=None): """ Remove all failed jobs from the database, optional with `search` pattern """ search = convert_search(search) logging.info('Removing all failed jobs from history') return self.execute("""DELETE FROM history WHERE name LIKE ? AND status = 'Failed'""", (search,), save=True) def remove_history(self, jobs=None): """ Remove all jobs in the list `jobs`, empty list will remove all completed jobs """ if jobs is None: self.remove_completed() else: if not isinstance(jobs, list): jobs = [jobs] for job in jobs: self.execute("""DELETE FROM history WHERE nzo_id=?""", (job,), save=True) logging.info('[%s] Removing job %s from history', caller_name(), job) def auto_history_purge(self): """ Remove history items based on the configured history-retention """ if sabnzbd.cfg.history_retention() == "0": return if sabnzbd.cfg.history_retention() == "-1": # Delete all non-failed ones self.remove_completed() if "d" in sabnzbd.cfg.history_retention(): # How many days to keep? days_to_keep = int_conv(sabnzbd.cfg.history_retention().strip()[:-1]) seconds_to_keep = int(time.time()) - days_to_keep * 86400 if days_to_keep > 0: logging.info('Removing completed jobs older than %s days from history', days_to_keep) return self.execute("""DELETE FROM history WHERE status = 'Completed' AND completed < ?""", (seconds_to_keep,), save=True) else: # How many to keep? to_keep = int_conv(sabnzbd.cfg.history_retention()) if to_keep > 0: logging.info('Removing all but last %s completed jobs from history', to_keep) return self.execute("""DELETE FROM history WHERE id NOT IN ( SELECT id FROM history WHERE status = 'Completed' ORDER BY completed DESC LIMIT ? )""", (to_keep,), save=True) def add_history_db(self, nzo, storage, path, postproc_time, script_output, script_line): """ Add a new job entry to the database """ t = build_history_info(nzo, storage, path, postproc_time, script_output, script_line) self.execute("""INSERT INTO history (completed, name, nzb_name, category, pp, script, report, url, status, nzo_id, storage, path, script_log, script_line, download_time, postproc_time, stage_log, downloaded, completeness, fail_message, url_info, bytes, series, md5sum, password) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", t, save=True) logging.info('Added job %s to history', nzo.final_name) def fetch_history(self, start=None, limit=None, search=None, failed_only=0, categories=None): """ Return records for specified jobs """ command_args = [convert_search(search)] post = '' if categories: categories = ['*' if c == 'Default' else c for c in categories] post = " AND (CATEGORY = ?" post += " OR CATEGORY = ? " * (len(categories) - 1) post += ")" command_args.extend(categories) if failed_only: post += ' AND STATUS = "Failed"' cmd = 'SELECT COUNT(*) FROM history WHERE name LIKE ?' res = self.execute(cmd + post, tuple(command_args)) total_items = -1 if res: try: total_items = self.c.fetchone().get('COUNT(*)') except AttributeError: pass if not start: start = 0 if not limit: limit = total_items command_args.extend([start, limit]) cmd = 'SELECT * FROM history WHERE name LIKE ?' fetch_ok = self.execute(cmd + post + ' ORDER BY completed desc LIMIT ?, ?', tuple(command_args)) if fetch_ok: items = self.c.fetchall() else: items = [] fetched_items = len(items) # Unpack the single line stage log # Stage Name is separated by ::: stage lines by ; and stages by \r\n items = [unpack_history_info(item) for item in items] return (items, fetched_items, total_items) def have_episode(self, series, season, episode): """ Check whether History contains this series episode """ total = 0 series = series.lower().replace('.', ' ').replace('_', ' ').replace(' ', ' ') if series and season and episode: pattern = '%s/%s/%s' % (series, season, episode) res = self.execute("select count(*) from History WHERE series = ? AND STATUS != 'Failed'", (pattern,)) if res: try: total = self.c.fetchone().get('count(*)') except AttributeError: pass return total > 0 def have_md5sum(self, md5sum): """ Check whether this md5sum already in History """ total = 0 res = self.execute("select count(*) from History WHERE md5sum = ? AND STATUS != 'Failed'", (md5sum,)) if res: try: total = self.c.fetchone().get('count(*)') except AttributeError: pass return total > 0 def get_history_size(self): """ Returns the total size of the history and amounts downloaded in the last month and week """ # Total Size of the history total = 0 if self.execute('''SELECT sum(bytes) FROM history'''): try: total = self.c.fetchone().get('sum(bytes)') except AttributeError: pass # Amount downloaded this month # r = time.gmtime(time.time()) # month_timest = int(time.mktime((r.tm_year, r.tm_mon, 0, 0, 0, 1, r.tm_wday, r.tm_yday, r.tm_isdst))) month_timest = int(this_month(time.time())) month = 0 if self.execute('''SELECT sum(bytes) FROM history WHERE "completed">?''', (month_timest,)): try: month = self.c.fetchone().get('sum(bytes)') except AttributeError: pass # Amount downloaded this week week_timest = int(this_week(time.time())) week = 0 if self.execute('''SELECT sum(bytes) FROM history WHERE "completed">?''', (week_timest,)): try: week = self.c.fetchone().get('sum(bytes)') except AttributeError: pass return (total, month, week) def get_script_log(self, nzo_id): """ Return decompressed log file """ data = '' t = (nzo_id,) if self.execute('SELECT script_log FROM history WHERE nzo_id=?', t): try: data = zlib.decompress(self.c.fetchone().get('script_log')) except: pass return data def get_name(self, nzo_id): """ Return name of the job `nzo_id` """ t = (nzo_id,) name = '' if self.execute('SELECT name FROM history WHERE nzo_id=?', t): try: name = self.c.fetchone().get('name') except AttributeError: pass return name def get_path(self, nzo_id): """ Return the `incomplete` path of the job `nzo_id` """ t = (nzo_id,) path = '' if self.execute('SELECT path FROM history WHERE nzo_id=?', t): try: path = self.c.fetchone().get('path') except AttributeError: pass return path def get_other(self, nzo_id): """ Return additional data for job `nzo_id` """ t = (nzo_id,) if self.execute('SELECT * FROM history WHERE nzo_id=?', t): try: items = self.c.fetchall()[0] dtype = items.get('report') url = items.get('url') pp = items.get('pp') script = items.get('script') cat = items.get('category') except (AttributeError, IndexError): return '', '', '', '', '' return dtype, url, pp, script, cat def dict_factory(cursor, row): """ Return a dictionary for the current database position """ d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d _PP_LOOKUP = {0: '', 1: 'R', 2: 'U', 3: 'D'} def build_history_info(nzo, storage='', downpath='', postproc_time=0, script_output='', script_line=''): """ Collects all the information needed for the database """ if not downpath: downpath = nzo.downpath path = decode_factory(downpath) storage = decode_factory(storage) script_line = decode_factory(script_line) flagRepair, flagUnpack, flagDelete = nzo.repair_opts nzo_info = decode_factory(nzo.nzo_info) url = decode_factory(nzo.url) completed = int(time.time()) name = decode_factory(nzo.final_name) nzb_name = decode_factory(nzo.filename) category = decode_factory(nzo.cat) pp = _PP_LOOKUP.get(sabnzbd.opts_to_pp(flagRepair, flagUnpack, flagDelete), 'X') script = decode_factory(nzo.script) status = decode_factory(nzo.status) nzo_id = nzo.nzo_id bytes = nzo.bytes_downloaded if script_output: # Compress the output of the script script_log = sqlite3.Binary(zlib.compress(script_output)) # else: script_log = '' download_time = decode_factory(nzo_info.get('download_time', 0)) downloaded = nzo.bytes_downloaded completeness = 0 fail_message = decode_factory(nzo.fail_msg) url_info = nzo_info.get('details', '') or nzo_info.get('more_info', '') # Get the dictionary containing the stages and their unpack process stages = decode_factory(nzo.unpack_info) # Pack the dictionary up into a single string # Stage Name is separated by ::: stage lines by ; and stages by \r\n lines = [] for key, results in stages.iteritems(): lines.append('%s:::%s' % (key, ';'.join(results))) stage_log = '\r\n'.join(lines) # Reuse the old 'report' column to indicate a URL-fetch report = 'future' if nzo.futuretype else '' # Analyze series info only when job is finished series = u'' if postproc_time: seriesname, season, episode, dummy = sabnzbd.newsunpack.analyse_show(nzo.final_name) if seriesname and season and episode: series = u'%s/%s/%s' % (seriesname.lower(), season, episode) return (completed, name, nzb_name, category, pp, script, report, url, status, nzo_id, storage, path, script_log, script_line, download_time, postproc_time, stage_log, downloaded, completeness, fail_message, url_info, bytes, series, nzo.md5sum, nzo.password) def unpack_history_info(item): """ Expands the single line stage_log from the DB into a python dictionary for use in the history display """ # Stage Name is separated by ::: stage lines by ; and stages by \r\n lst = item['stage_log'] if lst: try: lines = lst.split('\r\n') except: logging.error(T('Invalid stage logging in history for %s') + ' (\\r\\n)', unicoder(item['name'])) logging.debug('Lines: %s', lst) lines = [] lst = [None for x in STAGES] for line in lines: stage = {} try: key, logs = line.split(':::') except: logging.debug('Missing key:::logs "%s"', line) key = line logs = '' stage['name'] = key stage['actions'] = [] try: logs = logs.split(';') except: logging.error(T('Invalid stage logging in history for %s') + ' (;)', unicoder(item['name'])) logging.debug('Logs: %s', logs) logs = [] for log in logs: stage['actions'].append(log) try: lst[STAGES[key]] = stage except KeyError: lst.append(stage) # Remove unused stages item['stage_log'] = [x for x in lst if x is not None] if item['script_log']: item['script_log'] = '' # The action line is only available for items in the postproc queue if 'action_line' not in item: item['action_line'] = '' return item def midnight_history_purge(): logging.info('Scheduled history purge') history_db = HistoryDB() history_db.auto_history_purge() history_db.close() def decode_factory(text): """ Recursively looks through the supplied argument and converts and text to Unicode """ if isinstance(text, str): return unicoder(text) elif isinstance(text, list): new_text = [] for t in text: new_text.append(decode_factory(t)) return new_text elif isinstance(text, dict): new_text = {} for key in text: new_text[key] = decode_factory(text[key]) return new_text else: return text SABnzbd-2.3.2/sabnzbd/decoder.py0000644000000000000000000003377113217005257014546 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.decoder - article decoder """ import binascii import logging import re import hashlib from time import sleep from threading import Thread import sabnzbd from sabnzbd.constants import Status, MAX_DECODE_QUEUE, LIMIT_DECODE_QUEUE, SABYENC_VERSION_REQUIRED import sabnzbd.articlecache import sabnzbd.downloader import sabnzbd.nzbqueue import sabnzbd.cfg as cfg from sabnzbd.encoding import yenc_name_fixer from sabnzbd.misc import match_str # Check for basic-yEnc try: import _yenc HAVE_YENC = True except ImportError: HAVE_YENC = False # Check for correct SABYenc version SABYENC_VERSION = None try: import sabyenc SABYENC_ENABLED = True SABYENC_VERSION = sabyenc.__version__ # Verify version to at least match minor version if SABYENC_VERSION[:3] != SABYENC_VERSION_REQUIRED[:3]: raise ImportError except ImportError: SABYENC_ENABLED = False class CrcError(Exception): def __init__(self, needcrc, gotcrc, data): Exception.__init__(self) self.needcrc = needcrc self.gotcrc = gotcrc self.data = data class BadYenc(Exception): def __init__(self): Exception.__init__(self) YDEC_TRANS = ''.join([chr((i + 256 - 42) % 256) for i in xrange(256)]) class Decoder(Thread): def __init__(self, servers, queue): Thread.__init__(self) self.queue = queue self.servers = servers self.__log_decoding = cfg.debug_log_decoding() def stop(self): # Put multiple to stop all decoders self.queue.put(None) self.queue.put(None) def run(self): while 1: # Sleep to allow decoder/assembler switching sleep(0.0001) art_tup = self.queue.get() if not art_tup: break article, lines, raw_data = art_tup nzf = article.nzf nzo = nzf.nzo art_id = article.article killed = False # Check if the space that's now free can let us continue the queue? qsize = self.queue.qsize() if (sabnzbd.articlecache.ArticleCache.do.free_reserve_space(lines) or qsize < MAX_DECODE_QUEUE) and \ (qsize < LIMIT_DECODE_QUEUE) and sabnzbd.downloader.Downloader.do.delayed: sabnzbd.downloader.Downloader.do.undelay() data = None register = True # Finish article found = False # Proper article found logme = None if lines or raw_data: try: if nzo.precheck: raise BadYenc register = True if self.__log_decoding: logging.debug("Decoding %s", art_id) data = self.decode(article, lines, raw_data) nzf.article_count += 1 found = True except IOError, e: logme = T('Decoding %s failed') % art_id logging.warning(logme) logging.info("Traceback: ", exc_info=True) sabnzbd.downloader.Downloader.do.pause() sabnzbd.nzbqueue.NzbQueue.do.reset_try_lists(article) register = False except MemoryError, e: logme = T('Decoder failure: Out of memory') logging.warning(logme) anfo = sabnzbd.articlecache.ArticleCache.do.cache_info() logging.info("Decoder-Queue: %d, Cache: %d, %d, %d", self.queue.qsize(), anfo.article_sum, anfo.cache_size, anfo.cache_limit) logging.info("Traceback: ", exc_info=True) sabnzbd.downloader.Downloader.do.pause() sabnzbd.nzbqueue.NzbQueue.do.reset_try_lists(article) register = False except CrcError, e: logme = 'CRC Error in %s' % art_id logging.info(logme) data = e.data except (BadYenc, ValueError): # Handles precheck and badly formed articles killed = False found = False data_to_check = lines or raw_data if nzo.precheck and data_to_check and data_to_check[0].startswith('223 '): # STAT was used, so we only get a status code found = True else: # Examine headers (for precheck) or body (for download) # And look for DMCA clues (while skipping "X-" headers) for line in data_to_check: lline = line.lower() if 'message-id:' in lline: found = True if not line.startswith('X-') and match_str(lline, ('dmca', 'removed', 'cancel', 'blocked')): killed = True break if killed: logme = 'Article removed from server (%s)' logging.info(logme, art_id) if nzo.precheck: if found and not killed: # Pre-check, proper article found, just register logging.debug('Server %s has article %s', article.fetcher, art_id) register = True elif not killed and not found: logme = T('Badly formed yEnc article in %s') % art_id logging.info(logme) if not found or killed: new_server_found = self.search_new_server(article) if new_server_found: register = False logme = None except: logme = T('Unknown Error while decoding %s') % art_id logging.info(logme) logging.info("Traceback: ", exc_info=True) new_server_found = self.search_new_server(article) if new_server_found: register = False logme = None if logme: if killed: nzo.increase_bad_articles_counter('killed_articles') else: nzo.increase_bad_articles_counter('bad_articles') else: new_server_found = self.search_new_server(article) if new_server_found: register = False elif nzo.precheck: found = False if data: sabnzbd.articlecache.ArticleCache.do.save_article(article, data) if register: sabnzbd.nzbqueue.NzbQueue.do.register_article(article, found) def decode(self, article, data, raw_data): # Do we have SABYenc? Let it do all the work if sabnzbd.decoder.SABYENC_ENABLED: decoded_data, output_filename, crc, crc_expected, crc_correct = sabyenc.decode_usenet_chunks(raw_data, article.bytes) # Assume it is yenc article.nzf.type = 'yenc' # Only set the name if it was found and not obfuscated self.verify_filename(article, decoded_data, output_filename) # CRC check if not crc_correct: raise CrcError(crc_expected, crc, decoded_data) return decoded_data # Continue for _yenc or Python-yEnc # Filter out empty ones data = filter(None, data) # No point in continuing if we don't have any data left if data: nzf = article.nzf yenc, data = yCheck(data) ybegin, ypart, yend = yenc decoded_data = None # Deal with non-yencoded posts if not ybegin: found = False try: for i in xrange(min(40, len(data))): if data[i].startswith('begin '): nzf.type = 'uu' found = True # Pause the job and show warning if nzf.nzo.status != Status.PAUSED: nzf.nzo.pause() msg = T('UUencode detected, only yEnc encoding is supported [%s]') % nzf.nzo.final_name logging.warning(msg) break except IndexError: raise BadYenc() if found: decoded_data = '' else: raise BadYenc() # Deal with yenc encoded posts elif ybegin and yend: if 'name' in ybegin: output_filename = yenc_name_fixer(ybegin['name']) else: output_filename = None logging.debug("Possible corrupt header detected => ybegin: %s", ybegin) nzf.type = 'yenc' # Decode data if HAVE_YENC: decoded_data, crc = _yenc.decode_string(''.join(data))[:2] partcrc = '%08X' % ((crc ^ -1) & 2 ** 32L - 1) else: data = ''.join(data) for i in (0, 9, 10, 13, 27, 32, 46, 61): j = '=%c' % (i + 64) data = data.replace(j, chr(i)) decoded_data = data.translate(YDEC_TRANS) crc = binascii.crc32(decoded_data) partcrc = '%08X' % (crc & 2 ** 32L - 1) if ypart: crcname = 'pcrc32' else: crcname = 'crc32' if crcname in yend: _partcrc = yenc_name_fixer('0' * (8 - len(yend[crcname])) + yend[crcname].upper()) else: _partcrc = None logging.debug("Corrupt header detected => yend: %s", yend) if not _partcrc == partcrc: raise CrcError(_partcrc, partcrc, decoded_data) else: raise BadYenc() # Parse filename if there was data if decoded_data: # Only set the name if it was found and not obfuscated self.verify_filename(article, decoded_data, output_filename) return decoded_data def search_new_server(self, article): # Search new server article.add_to_try_list(article.fetcher) for server in self.servers: if server.active and not article.server_in_try_list(server): if server.priority >= article.fetcher.priority: article.tries = 0 # Allow all servers for this nzo and nzf again (but not for this article) sabnzbd.nzbqueue.NzbQueue.do.reset_try_lists(article, article_reset=False) return True msg = T('%s => missing from all servers, discarding') % article logging.info(msg) article.nzf.nzo.increase_bad_articles_counter('missing_articles') return False def verify_filename(self, article, decoded_data, yenc_filename): """ Verify the filename provided by yenc by using par2 information and otherwise fall back to NZB name """ nzf = article.nzf # Was this file already verified and did we get a name? if nzf.filename_checked or not yenc_filename: return # Set the md5-of-16k if this is the first article if article.lowest_partnum: nzf.md5of16k = hashlib.md5(decoded_data[:16384]).digest() # Try the rename nzf.nzo.verify_nzf_filename(nzf, yenc_filename) def yCheck(data): ybegin = None ypart = None yend = None # Check head for i in xrange(min(40, len(data))): try: if data[i].startswith('=ybegin '): splits = 3 if data[i].find(' part=') > 0: splits += 1 if data[i].find(' total=') > 0: splits += 1 ybegin = ySplit(data[i], splits) if data[i + 1].startswith('=ypart '): ypart = ySplit(data[i + 1]) data = data[i + 2:] break else: data = data[i + 1:] break except IndexError: break # Check tail for i in xrange(-1, -11, -1): try: if data[i].startswith('=yend '): yend = ySplit(data[i]) data = data[:i] break except IndexError: break return ((ybegin, ypart, yend), data) # Example: =ybegin part=1 line=128 size=123 name=-=DUMMY=- abc.par YSPLIT_RE = re.compile(r'([a-zA-Z0-9]+)=') def ySplit(line, splits=None): fields = {} if splits: parts = YSPLIT_RE.split(line, splits)[1:] else: parts = YSPLIT_RE.split(line)[1:] if len(parts) % 2: return fields for i in range(0, len(parts), 2): key, value = parts[i], parts[i + 1] fields[key] = value.strip() return fields SABnzbd-2.3.2/sabnzbd/decorators.py0000644000000000000000000000351313217005257015275 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ############################################################################## # Decorators ############################################################################## from threading import RLock, Condition # All operations that modify the queue need to happen in a lock # Also used when importing NZBs to prevent IO-race conditions # Names of wrapper-functions should be the same in misc.caller_name # The NzbQueueLocker both locks and notifies the Downloader NZBQUEUE_LOCK = RLock() DOWNLOADER_CV = Condition(NZBQUEUE_LOCK) def synchronized(lock): def wrap(f): def call_func(*args, **kw): lock.acquire() try: return f(*args, **kw) finally: lock.release() return call_func return wrap def NzbQueueLocker(func): global DOWNLOADER_CV def call_func(*params, **kparams): DOWNLOADER_CV.acquire() try: return func(*params, **kparams) finally: DOWNLOADER_CV.notify_all() DOWNLOADER_CV.release() return call_func SABnzbd-2.3.2/sabnzbd/directunpacker.py0000644000000000000000000004337613217005257016146 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.directunpacker """ import os import re import time import threading import subprocess import logging import sabnzbd import sabnzbd.cfg as cfg from sabnzbd.misc import int_conv, clip_path, long_path, remove_all, globber, \ format_time_string, has_win_device, real_path, remove_file from sabnzbd.encoding import TRANS, unicoder from sabnzbd.newsunpack import build_command, EXTRACTFROM_RE, EXTRACTED_RE, rar_volumelist from sabnzbd.postproc import prepare_extraction_path from sabnzbd.utils.rarfile import RarFile from sabnzbd.utils.diskspeed import diskspeedmeasure if sabnzbd.WIN32: try: # Use patched version of subprocess module for Unicode on Windows import subprocessww except ImportError: pass # Load the regular POpen (which is now patched on Windows) from subprocess import Popen MAX_ACTIVE_UNPACKERS = 10 ACTIVE_UNPACKERS = [] RAR_NR = re.compile(r'(.*?)(\.part(\d*).rar|\.r(\d*))$', re.IGNORECASE) class DirectUnpacker(threading.Thread): def __init__(self, nzo): threading.Thread.__init__(self) self.nzo = nzo self.active_instance = None self.killed = False self.next_file_lock = threading.Condition(threading.RLock()) self.unpack_dir_info = None self.rarfile_nzf = None self.cur_setname = None self.cur_volume = 0 self.total_volumes = {} self.unpack_time = 0.0 self.success_sets = {} self.next_sets = [] nzo.direct_unpacker = self def stop(self): pass def save(self): pass def reset_active(self): self.active_instance = None self.cur_setname = None self.cur_volume = 0 self.rarfile_nzf = None def check_requirements(self): if not cfg.direct_unpack() or self.killed or not self.nzo.unpack or self.nzo.bad_articles or sabnzbd.newsunpack.RAR_PROBLEM: return False return True def set_volumes_for_nzo(self): """ Loop over all files to detect the names """ none_counter = 0 found_counter = 0 for nzf in self.nzo.files + self.nzo.finished_files: nzf.setname, nzf.vol = analyze_rar_filename(nzf.filename) # We matched? if nzf.setname: found_counter += 1 if nzf.setname not in self.total_volumes: self.total_volumes[nzf.setname] = 0 self.total_volumes[nzf.setname] = max(self.total_volumes[nzf.setname], nzf.vol) else: none_counter += 1 # Too much not found? Obfuscated, ignore results if none_counter > found_counter: self.total_volumes = {} def add(self, nzf): """ Add jobs and start instance of DirectUnpack """ if not cfg.direct_unpack_tested(): test_disk_performance() # Stop if something is wrong if not self.check_requirements(): return # Is this the first set? if not self.cur_setname: self.set_volumes_for_nzo() self.cur_setname = nzf.setname # Analyze updated filenames nzf.setname, nzf.vol = analyze_rar_filename(nzf.filename) # Are we doing this set? if self.cur_setname == nzf.setname: logging.debug('DirectUnpack queued %s for %s', nzf.filename, self.cur_setname) # Is this the first one of the first set? if not self.active_instance and not self.is_alive() and self.have_next_volume(): # Too many runners already? if len(ACTIVE_UNPACKERS) >= cfg.direct_unpack_threads(): logging.info('Too many DirectUnpackers currently to start %s', self.cur_setname) return # Start the unrar command and the loop self.create_unrar_instance() self.start() elif not any(test_nzf.setname == nzf.setname for test_nzf in self.next_sets): # Need to store this for the future, only once per set! self.next_sets.append(nzf) # Wake up the thread to see if this is good to go with self.next_file_lock: self.next_file_lock.notify() def run(self): # Input and output linebuf = '' last_volume_linebuf = '' unrar_log = [] rarfiles = [] extracted = [] start_time = time.time() # Need to read char-by-char because there's no newline after new-disk message while 1: if not self.active_instance: break char = self.active_instance.stdout.read(1) linebuf += char if not char: # End of program break # Error? Let PP-handle it if linebuf.endswith(('ERROR: ', 'Cannot create', 'in the encrypted file', 'CRC failed', \ 'checksum failed', 'You need to start extraction from a previous volume', \ 'password is incorrect', 'Write error', 'checksum error', \ 'start extraction from a previous volume')): logging.info('Error in DirectUnpack of %s', self.cur_setname) self.abort() if linebuf.endswith('\n'): # List files we used if linebuf.startswith('Extracting from'): filename = TRANS((re.search(EXTRACTFROM_RE, linebuf.strip()).group(1))) if filename not in rarfiles: rarfiles.append(filename) # List files we extracted m = re.search(EXTRACTED_RE, linebuf) if m: # In case of flat-unpack, UnRar still prints the whole path (?!) unpacked_file = TRANS(m.group(2)) if cfg.flat_unpack(): unpacked_file = os.path.basename(unpacked_file) extracted.append(real_path(self.unpack_dir_info[0], unpacked_file)) # Did we reach the end? if linebuf.endswith('All OK'): # Stop timer and finish self.unpack_time += time.time() - start_time ACTIVE_UNPACKERS.remove(self) # Add to success rarfile_path = os.path.join(self.nzo.downpath, self.rarfile_nzf.filename) self.success_sets[self.cur_setname] = (rar_volumelist(rarfile_path, self.nzo.password, rarfiles), extracted) logging.info('DirectUnpack completed for %s', self.cur_setname) self.nzo.set_action_line(T('Direct Unpack'), T('Completed')) # List success in history-info msg = T('Unpacked %s files/folders in %s') % (len(extracted), format_time_string(self.unpack_time)) msg = '%s - %s' % (T('Direct Unpack'), msg) self.nzo.set_unpack_info('Unpack', '[%s] %s' % (unicoder(self.cur_setname), msg)) # Write current log and clear unrar_log.append(linebuf.strip()) linebuf = '' last_volume_linebuf = '' logging.debug('DirectUnpack Unrar output %s', '\n'.join(unrar_log)) unrar_log = [] rarfiles = [] extracted = [] # Are there more files left? while self.nzo.files and not self.next_sets: with self.next_file_lock: self.next_file_lock.wait() # Is there another set to do? if self.next_sets: # Start new instance nzf = self.next_sets.pop(0) self.reset_active() self.cur_setname = nzf.setname # Wait for the 1st volume to appear self.wait_for_next_volume() self.create_unrar_instance() start_time = time.time() else: self.killed = True break if linebuf.endswith('[C]ontinue, [Q]uit '): # Stop timer self.unpack_time += time.time() - start_time # Wait for the next one.. self.wait_for_next_volume() # Possible that the instance was deleted while locked if not self.killed: # If unrar stopped or is killed somehow, writing will cause a crash try: # Give unrar some time to do it's thing self.active_instance.stdin.write('C\n') start_time = time.time() time.sleep(0.1) except IOError: self.abort() break # Did we unpack a new volume? Sometimes UnRar hangs on 1 volume if not last_volume_linebuf or last_volume_linebuf != linebuf: # Next volume self.cur_volume += 1 self.nzo.set_action_line(T('Direct Unpack'), self.get_formatted_stats()) logging.info('DirectUnpacked volume %s for %s', self.cur_volume, self.cur_setname) # If lines did not change and we don't have the next volume, this download is missing files! if last_volume_linebuf == linebuf: if not self.have_next_volume(): logging.info('DirectUnpack failed due to missing files %s', self.cur_setname) self.abort() else: logging.debug('Duplicate output line detected: "%s"', last_volume_linebuf) last_volume_linebuf = linebuf # Show the log if linebuf.endswith('\n'): unrar_log.append(linebuf.strip()) linebuf = '' # Add last line unrar_log.append(linebuf.strip()) logging.debug('DirectUnpack Unrar output %s', '\n'.join(unrar_log)) # Make more space self.reset_active() if self in ACTIVE_UNPACKERS: ACTIVE_UNPACKERS.remove(self) # Set the thread to killed so it never gets restarted by accident self.killed = True def have_next_volume(self): """ Check if next volume of set is available, start from the end of the list where latest completed files are Make sure that files are 100% written to disk by checking md5sum """ for nzf_search in reversed(self.nzo.finished_files): if nzf_search.setname == self.cur_setname and nzf_search.vol == (self.cur_volume+1) and nzf_search.md5sum: return nzf_search return False def wait_for_next_volume(self): """ Wait for the correct volume to appear But stop if it was killed or the NZB is done """ while not self.have_next_volume() and not self.killed and self.nzo.files: with self.next_file_lock: self.next_file_lock.wait() def create_unrar_instance(self): """ Start the unrar instance using the user's options """ # Generate extraction path and save for post-proc if not self.unpack_dir_info: try: self.unpack_dir_info = prepare_extraction_path(self.nzo) except: # Prevent fatal crash if directory creation fails self.abort() return # Get the information extraction_path, _, _, one_folder, _ = self.unpack_dir_info # Set options if self.nzo.password: password_command = '-p%s' % self.nzo.password else: password_command = '-p-' if one_folder or cfg.flat_unpack(): action = 'e' else: action = 'x' # The first NZF self.rarfile_nzf = self.have_next_volume() # Generate command rarfile_path = os.path.join(self.nzo.downpath, self.rarfile_nzf.filename) if sabnzbd.WIN32: # For Unrar to support long-path, we need to cricumvent Python's list2cmdline # See: https://github.com/sabnzbd/sabnzbd/issues/1043 command = ['%s' % sabnzbd.newsunpack.RAR_COMMAND, action, '-vp', '-idp', '-o+', '-ai', password_command, '%s' % clip_path(rarfile_path), '%s\\' % long_path(extraction_path)] else: # Don't use "-ai" (not needed for non-Windows) command = ['%s' % sabnzbd.newsunpack.RAR_COMMAND, action, '-vp', '-idp', '-o+', password_command, '%s' % rarfile_path, '%s/' % extraction_path] if cfg.ignore_unrar_dates(): command.insert(3, '-tsm-') # Let's start from the first one! self.cur_volume = 1 stup, need_shell, command, creationflags = build_command(command, flatten_command=True) logging.debug('Running unrar for DirectUnpack %s', command) self.active_instance = Popen(command, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, creationflags=creationflags) # Add to runners ACTIVE_UNPACKERS.append(self) # Doing the first logging.info('DirectUnpacked volume %s for %s', self.cur_volume, self.cur_setname) def abort(self): """ Abort running instance and delete generated files """ if not self.killed: logging.info('Aborting DirectUnpack for %s', self.cur_setname) self.killed = True # Save reference to the first rarfile rarfile_nzf = self.rarfile_nzf # Abort Unrar if self.active_instance: self.active_instance.kill() # We need to wait for it to kill the process self.active_instance.wait() # Wake up the thread with self.next_file_lock: self.next_file_lock.notify() # No new sets self.next_sets = [] self.success_sets = {} # Remove files if self.unpack_dir_info: extraction_path, _, _, one_folder, _ = self.unpack_dir_info # In case of flat-unpack we need to remove the files manually if one_folder: # RarFile can fail for mysterious reasons try: rar_contents = RarFile(os.path.join(self.nzo.downpath, rarfile_nzf.filename), all_names=True).filelist() for rm_file in rar_contents: # Flat-unpack, so remove foldername from RarFile output f = os.path.join(extraction_path, os.path.basename(rm_file)) remove_file(f) except: # The user will have to remove it themselves logging.info('Failed to clean Direct Unpack after aborting %s', rarfile_nzf.filename, exc_info=True) pass else: # We can just remove the whole path remove_all(extraction_path, recursive=True) # Remove dir-info self.unpack_dir_info = None # Reset settings self.reset_active() def get_formatted_stats(self): """ Get percentage or number of rar's done """ if self.cur_setname and self.cur_setname in self.total_volumes: # This won't work on obfuscated posts if self.total_volumes[self.cur_setname] >= self.cur_volume and self.cur_volume: return '%02d/%02d' % (self.cur_volume, self.total_volumes[self.cur_setname]) return self.cur_volume def analyze_rar_filename(filename): """ Extract volume number and setname from rar-filenames Both ".part01.rar" and ".r01" """ m = RAR_NR.search(filename) if m: if m.group(4): # Special since starts with ".rar", ".r00" return m.group(1), int_conv(m.group(4)) + 2 return m.group(1), int_conv(m.group(3)) else: # Detect if first of "rxx" set if filename.endswith('.rar'): return os.path.splitext(filename)[0], 1 return None, None def abort_all(): """ Abort all running DirectUnpackers """ logging.info('Aborting all DirectUnpackers') for direct_unpacker in ACTIVE_UNPACKERS: direct_unpacker.abort() def test_disk_performance(): """ Test the incomplete-dir performance and enable Direct Unpack if good enough (> 40MB/s) """ if diskspeedmeasure(sabnzbd.cfg.download_dir.get_path()) > 40: cfg.direct_unpack.set(True) logging.warning(T('Direct Unpack was automatically enabled.') + ' ' + T('Jobs will start unpacking during the downloading to reduce post-processing time. Only works for jobs that do not need repair.')) else: logging.info('Direct Unpack was not enabled, incomplete folder disk speed below 40MB/s') cfg.direct_unpack_tested.set(True) sabnzbd.config.save_config() SABnzbd-2.3.2/sabnzbd/dirscanner.py0000644000000000000000000003744413217005257015272 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.dirscanner - Scanner for Watched Folder """ import os import time import logging import zipfile import gzip import bz2 import threading import sabnzbd from sabnzbd.constants import SCAN_FILE_NAME, VALID_ARCHIVES import sabnzbd.utils.rarfile as rarfile from sabnzbd.encoding import platform_encode from sabnzbd.decorators import NzbQueueLocker from sabnzbd.newsunpack import is_sevenfile, SevenZip import sabnzbd.nzbstuff as nzbstuff import sabnzbd.misc as misc import sabnzbd.config as config import sabnzbd.cfg as cfg def name_to_cat(fname, cat=None): """ Retrieve category from file name, but only if "cat" is None. """ if cat is None and fname.startswith('{{'): n = fname.find('}}') if n > 2: cat = fname[2:n].strip() fname = fname[n + 2:].strip() logging.debug('Job %s has category %s', fname, cat) return fname, cat def CompareStat(tup1, tup2): """ Test equality of two stat-tuples, content-related parts only """ if tup1.st_ino != tup2.st_ino: return False if tup1.st_size != tup2.st_size: return False if tup1.st_mtime != tup2.st_mtime: return False if tup1.st_ctime != tup2.st_ctime: return False return True def is_archive(path): """ Check if file in path is an ZIP, RAR or 7z file :param path: path to file :return: (zf, status, expected_extension) status: -1==Error/Retry, 0==OK, 1==Ignore """ if zipfile.is_zipfile(path): try: zf = zipfile.ZipFile(path) return 0, zf, '.zip' except: logging.info(T('Cannot read %s'), path, exc_info=True) return -1, None, '' elif rarfile.is_rarfile(path): try: # Set path to tool to open it rarfile.UNRAR_TOOL = sabnzbd.newsunpack.RAR_COMMAND zf = rarfile.RarFile(path) return 0, zf, '.rar' except: logging.info(T('Cannot read %s'), path, exc_info=True) return -1, None, '' elif is_sevenfile(path): try: zf = SevenZip(path) return 0, zf, '.7z' except: logging.info(T('Cannot read %s'), path, exc_info=True) return -1, None, '' else: logging.info('Archive %s is not a real archive!', os.path.basename(path)) return 1, None, '' @NzbQueueLocker def ProcessArchiveFile(filename, path, pp=None, script=None, cat=None, catdir=None, keep=False, priority=None, url='', nzbname=None, password=None, nzo_id=None): """ Analyse ZIP file and create job(s). Accepts ZIP files with ONLY nzb/nfo/folder files in it. returns (status, nzo_ids) status: -1==Error/Retry, 0==OK, 1==Ignore """ nzo_ids = [] if catdir is None: catdir = cat filename, cat = name_to_cat(filename, catdir) status, zf, extension = is_archive(path) if status != 0: return status, [] status = 1 names = zf.namelist() nzbcount = 0 for name in names: name = name.lower() if name.endswith('.nzb'): status = 0 nzbcount += 1 if status == 0: if nzbcount != 1: nzbname = None for name in names: if name.lower().endswith('.nzb'): try: data = zf.read(name) except: logging.error(T('Cannot read %s'), name, exc_info=True) zf.close() return -1, [] name = os.path.basename(name) if data: nzo = None try: nzo = nzbstuff.NzbObject(name, pp, script, data, cat=cat, url=url, priority=priority, nzbname=nzbname) if not nzo.password: nzo.password = password except (TypeError, ValueError) as e: # Duplicate or empty, ignore pass except: # Something else is wrong, show error logging.error(T('Error while adding %s, removing'), name, exc_info=True) if nzo: if nzo_id: # Re-use existing nzo_id, when a "future" job gets it payload sabnzbd.nzbqueue.NzbQueue.do.remove(nzo_id, add_to_history=False) nzo.nzo_id = nzo_id nzo_id = None nzo_ids.append(sabnzbd.nzbqueue.NzbQueue.do.add(nzo)) nzo.update_rating() zf.close() try: if not keep: misc.remove_file(path) except: logging.error(T('Error removing %s'), misc.clip_path(path)) logging.info("Traceback: ", exc_info=True) status = 1 else: zf.close() status = 1 return status, nzo_ids @NzbQueueLocker def ProcessSingleFile(filename, path, pp=None, script=None, cat=None, catdir=None, keep=False, priority=None, nzbname=None, reuse=False, nzo_info=None, dup_check=True, url='', password=None, nzo_id=None): """ Analyze file and create a job from it Supports NZB, NZB.BZ2, NZB.GZ and GZ.NZB-in-disguise returns (status, nzo_ids) status: -2==Error/retry, -1==Error, 0==OK, 1==OK-but-ignorecannot-delete """ nzo_ids = [] if catdir is None: catdir = cat try: f = open(path, 'rb') b1 = f.read(1) b2 = f.read(1) f.close() if b1 == '\x1f' and b2 == '\x8b': # gzip file or gzip in disguise name = filename.replace('.nzb.gz', '.nzb') f = gzip.GzipFile(path, 'rb') elif b1 == 'B' and b2 == 'Z': # bz2 file or bz2 in disguise name = filename.replace('.nzb.bz2', '.nzb') f = bz2.BZ2File(path, 'rb') else: name = filename f = open(path, 'rb') data = f.read() f.close() except: logging.warning(T('Cannot read %s'), misc.clip_path(path)) logging.info("Traceback: ", exc_info=True) return -2, nzo_ids if name: name, cat = name_to_cat(name, catdir) # The name is used as the name of the folder, so sanitize it using folder specific santization if not nzbname: # Prevent embedded password from being damaged by sanitize and trimming nzbname = os.path.split(name)[1] try: nzo = nzbstuff.NzbObject(name, pp, script, data, cat=cat, priority=priority, nzbname=nzbname, nzo_info=nzo_info, url=url, reuse=reuse, dup_check=dup_check) if not nzo.password: nzo.password = password except TypeError: # Duplicate, ignore if nzo_id: sabnzbd.nzbqueue.NzbQueue.do.remove(nzo_id, add_to_history=False) nzo = None except ValueError: # Empty, but correct file return -1, nzo_ids except: if data.find("= 0 and data.find(" 0) and not self.shutdown and not self.trigger: time.sleep(1.0) x = x - 1 self.trigger = False if self.dirscan_speed and not self.shutdown: self.scan() def scan(self): """ Do one scan of the watched folder """ def run_dir(folder, catdir): try: files = os.listdir(folder) except: if not self.error_reported and not catdir: logging.error(T('Cannot read Watched Folder %s'), misc.clip_path(folder)) self.error_reported = True files = [] for filename in files: path = os.path.join(folder, platform_encode(filename)) if os.path.isdir(path) or path in self.ignored or filename[0] == '.': continue ext = os.path.splitext(path)[1].lower() candidate = ext in ('.nzb', '.gz', '.bz2') or ext in VALID_ARCHIVES if candidate: try: stat_tuple = os.stat(path) except: continue else: self.ignored[path] = 1 if path in self.suspected: if CompareStat(self.suspected[path], stat_tuple): # Suspected file still has the same attributes continue else: del self.suspected[path] if candidate and stat_tuple.st_size > 0: logging.info('Trying to import %s', path) # Wait until the attributes are stable for 1 second # but give up after 3 sec stable = False for n in xrange(3): time.sleep(1.0) try: stat_tuple_tmp = os.stat(path) except: continue if CompareStat(stat_tuple, stat_tuple_tmp): stable = True break else: stat_tuple = stat_tuple_tmp if not stable: continue # Handle archive files, but only when containing just NZB files if ext in VALID_ARCHIVES: res, nzo_ids = ProcessArchiveFile(filename, path, catdir=catdir, url=path) if res == -1: self.suspected[path] = stat_tuple elif res == 0: self.error_reported = False else: self.ignored[path] = 1 # Handle .nzb, .nzb.gz or gzip-disguised-as-nzb or .bz2 elif ext == '.nzb' or filename.lower().endswith('.nzb.gz') or filename.lower().endswith('.nzb.bz2'): res, nzo_id = ProcessSingleFile(filename, path, catdir=catdir, url=path) if res < 0: self.suspected[path] = stat_tuple elif res == 0: self.error_reported = False else: self.ignored[path] = 1 else: self.ignored[path] = 1 CleanList(self.ignored, folder, files) CleanList(self.suspected, folder, files) if not self.busy: self.busy = True dirscan_dir = self.dirscan_dir if dirscan_dir and not sabnzbd.PAUSED_ALL: run_dir(dirscan_dir, None) try: list = os.listdir(dirscan_dir) except: if not self.error_reported: logging.error(T('Cannot read Watched Folder %s'), misc.clip_path(dirscan_dir)) self.error_reported = True list = [] cats = config.get_categories() for dd in list: dpath = os.path.join(dirscan_dir, platform_encode(dd)) if os.path.isdir(dpath) and dd.lower() in cats: run_dir(dpath, dd.lower()) self.busy = False def dirscan(): """ Wrapper required for scheduler """ logging.info('Scheduled or manual watched folder scan') DirScanner.do.scan() SABnzbd-2.3.2/sabnzbd/downloader.py0000644000000000000000000011451413217005257015272 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.downloader - download engine """ import time import select import logging from threading import Thread, RLock from nntplib import NNTPPermanentError import socket import random import sys import Queue import sabnzbd from sabnzbd.decorators import synchronized, NzbQueueLocker, DOWNLOADER_CV from sabnzbd.constants import MAX_DECODE_QUEUE, LIMIT_DECODE_QUEUE from sabnzbd.decoder import Decoder from sabnzbd.newswrapper import NewsWrapper, request_server_info from sabnzbd.articlecache import ArticleCache import sabnzbd.notifier as notifier import sabnzbd.config as config import sabnzbd.cfg as cfg from sabnzbd.bpsmeter import BPSMeter import sabnzbd.scheduler from sabnzbd.misc import from_units, nntp_to_msg from sabnzbd.utils.happyeyeballs import happyeyeballs # Timeout penalty in minutes for each cause _PENALTY_UNKNOWN = 3 # Unknown cause _PENALTY_502 = 5 # Unknown 502 _PENALTY_TIMEOUT = 10 # Server doesn't give an answer (multiple times) _PENALTY_SHARE = 10 # Account sharing detected _PENALTY_TOOMANY = 10 # Too many connections _PENALTY_PERM = 10 # Permanent error, like bad username/password _PENALTY_SHORT = 1 # Minimal penalty when no_penalties is set _PENALTY_VERYSHORT = 0.1 # Error 400 without cause clues TIMER_LOCK = RLock() class Server(object): def __init__(self, id, displayname, host, port, timeout, threads, priority, ssl, ssl_verify, send_group, username=None, password=None, optional=False, retention=0): self.id = id self.newid = None self.restart = False self.displayname = displayname self.host = host self.port = port self.timeout = timeout self.threads = threads self.priority = priority self.ssl = ssl self.ssl_verify = ssl_verify self.optional = optional self.retention = retention self.send_group = send_group self.username = username self.password = password self.busy_threads = [] self.idle_threads = [] self.active = True self.bad_cons = 0 self.errormsg = '' self.warning = '' self.info = None # Will hold getaddrinfo() list self.ssl_info = '' # Will hold the type and cipher of SSL connection self.request = False # True if a getaddrinfo() request is pending self.have_body = 'free.xsusenet.com' not in host self.have_stat = True # Assume server has "STAT", until proven otherwise for i in range(threads): self.idle_threads.append(NewsWrapper(self, i + 1)) @property def hostip(self): """ In case a server still has active connections, we use the same IP again If new connection then based on value of load_balancing() and self.info: 0 - return the first entry, so all threads use the same IP 1 - and self.info has more than 1 entry (read: IP address): Return a random entry from the possible IPs 2 - and self.info has more than 1 entry (read: IP address): Return the quickest IP based on the happyeyeballs algorithm In case of problems: return the host name itself """ # Check if already a successful ongoing connection if self.busy_threads and self.busy_threads[0].nntp: # Re-use that IP logging.debug('%s: Re-using address %s', self.host, self.busy_threads[0].nntp.host) return self.busy_threads[0].nntp.host # Determine new IP if cfg.load_balancing() == 0 and self.info: # Just return the first one, so all next threads use the same IP ip = self.info[0][4][0] logging.debug('%s: Connecting to address %s', self.host, ip) elif cfg.load_balancing() == 1 and self.info and len(self.info) > 1: # Return a random entry from the possible IPs rnd = random.randint(0, len(self.info) - 1) ip = self.info[rnd][4][0] logging.debug('%s: Connecting to address %s', self.host, ip) elif cfg.load_balancing() == 2 and self.info and len(self.info) > 1: # RFC6555 / Happy Eyeballs: ip = happyeyeballs(self.host, port=self.port, ssl=self.ssl) if ip: logging.debug('%s: Connecting to address %s', self.host, ip) else: # nothing returned, so there was a connection problem ip = self.host logging.debug('%s: No successful IP connection was possible', self.host) else: ip = self.host return ip def stop(self, readers, writers): for nw in self.idle_threads: try: fno = nw.nntp.sock.fileno() except: fno = None if fno and fno in readers: readers.pop(fno) if fno and fno in writers: writers.pop(fno) nw.terminate(quit=True) self.idle_threads = [] def __repr__(self): return "%s:%s" % (self.host, self.port) class Downloader(Thread): """ Singleton Downloader Thread """ do = None def __init__(self, paused=False): Thread.__init__(self) logging.debug("Initializing downloader/decoder") # Used for scheduled pausing self.paused = paused # used for throttling bandwidth and scheduling bandwidth changes cfg.bandwidth_perc.callback(self.speed_set) cfg.bandwidth_max.callback(self.speed_set) self.speed_set() # Used for reducing speed self.delayed = False # Used to see if we can add a slowdown to the Downloader-loop self.can_be_slowed = None self.can_be_slowed_timer = 0 self.postproc = False self.shutdown = False # A user might change server parms again before server restart is ready. # Keep a counter to prevent multiple restarts self.__restart = 0 self.force_disconnect = False self.read_fds = {} self.write_fds = {} self.servers = [] self.server_dict = {} # For faster lookups, but is not updated later! self.server_nr = 0 self._timers = {} for server in config.get_servers(): self.init_server(None, server) self.decoder_queue = Queue.Queue() # Initialize decoders, only 1 for non-SABYenc self.decoder_workers = [] nr_decoders = 2 if sabnzbd.decoder.SABYENC_ENABLED else 1 for i in range(nr_decoders): self.decoder_workers.append(Decoder(self.servers, self.decoder_queue)) Downloader.do = self def init_server(self, oldserver, newserver): """ Setup or re-setup single server When oldserver is defined and in use, delay startup. Note that the server names are "host:port" strings! """ create = False servers = config.get_servers() if newserver in servers: srv = servers[newserver] enabled = srv.enable() displayname = srv.displayname() host = srv.host() port = srv.port() timeout = srv.timeout() threads = srv.connections() priority = srv.priority() ssl = srv.ssl() ssl_verify = srv.ssl_verify() username = srv.username() password = srv.password() optional = srv.optional() retention = float(srv.retention() * 24 * 3600) # days ==> seconds send_group = srv.send_group() create = True if oldserver: for n in xrange(len(self.servers)): if self.servers[n].id == oldserver: # Server exists, do re-init later create = False self.servers[n].newid = newserver self.servers[n].restart = True self.__restart += 1 break if create and enabled and host and port and threads: server = Server(newserver, displayname, host, port, timeout, threads, priority, ssl, ssl_verify, send_group, username, password, optional, retention) self.servers.append(server) self.server_dict[newserver] = server # Update server-count self.server_nr = len(self.servers) return @NzbQueueLocker def set_paused_state(self, state): """ Set downloader to specified paused state """ self.paused = state @NzbQueueLocker def resume(self): # Do not notify when SABnzbd is still starting if self.paused and sabnzbd.WEB_DIR: logging.info("Resuming") notifier.send_notification("SABnzbd", T('Resuming'), 'download') self.paused = False @NzbQueueLocker def pause(self): """ Pause the downloader, optionally saving admin """ if not self.paused: self.paused = True logging.info("Pausing") notifier.send_notification("SABnzbd", T('Paused'), 'download') if self.is_paused(): BPSMeter.do.reset() if cfg.autodisconnect(): self.disconnect() def delay(self): logging.debug("Delaying") self.delayed = True @NzbQueueLocker def undelay(self): logging.debug("Undelaying") self.delayed = False def wait_for_postproc(self): logging.info("Waiting for post-processing to finish") self.postproc = True @NzbQueueLocker def resume_from_postproc(self): logging.info("Post-processing finished, resuming download") self.postproc = False def disconnect(self): self.force_disconnect = True def limit_speed(self, value): ''' Set the actual download speed in Bytes/sec When 'value' ends with a '%' sign or is within 1-100, it is interpreted as a pecentage of the maximum bandwidth When no '%' is found, it is interpreted as an absolute speed (including KMGT notation). ''' if value: mx = cfg.bandwidth_max.get_int() if '%' in str(value) or (from_units(value) > 0 and from_units(value) < 101): limit = value.strip(' %') self.bandwidth_perc = from_units(limit) if mx: self.bandwidth_limit = mx * self.bandwidth_perc / 100 else: logging.warning(T('You must set a maximum bandwidth before you can set a bandwidth limit')) else: self.bandwidth_limit = from_units(value) if mx: self.bandwidth_perc = self.bandwidth_limit / mx * 100 else: self.bandwidth_perc = 100 else: self.speed_set() logging.info("Speed limit set to %s B/s", self.bandwidth_limit) def get_limit(self): return self.bandwidth_perc def get_limit_abs(self): return self.bandwidth_limit def speed_set(self): limit = cfg.bandwidth_max.get_int() perc = cfg.bandwidth_perc() if limit and perc: self.bandwidth_perc = perc self.bandwidth_limit = limit * perc / 100 else: self.bandwidth_perc = 0 self.bandwidth_limit = 0 def is_paused(self): if not self.paused: return False else: if sabnzbd.nzbqueue.NzbQueue.do.has_forced_items(): return False else: return True def highest_server(self, me): """ Return True when this server has the highest priority of the active ones 0 is the highest priority """ for server in self.servers: if server is not me and server.active and server.priority < me.priority: return False return True def nzo_servers(self, nzo): return filter(nzo.server_in_try_list, self.servers) def maybe_block_server(self, server): if server.optional and server.active and (server.bad_cons / server.threads) > 3: # Optional and active server had too many problems, # disable it now and send a re-enable plan to the scheduler server.bad_cons = 0 server.active = False server.errormsg = T('Server %s will be ignored for %s minutes') % ('', _PENALTY_TIMEOUT) logging.warning(T('Server %s will be ignored for %s minutes'), server.id, _PENALTY_TIMEOUT) self.plan_server(server.id, _PENALTY_TIMEOUT) # Remove all connections to server for nw in server.idle_threads + server.busy_threads: self.__reset_nw(nw, "forcing disconnect", warn=False, wait=False, quit=False) # Make sure server address resolution is refreshed server.info = None sabnzbd.nzbqueue.NzbQueue.do.reset_all_try_lists() def decode(self, article, lines, raw_data): self.decoder_queue.put((article, lines, raw_data)) # See if there's space left in cache, pause otherwise # But do allow some articles to enter queue, in case of full cache qsize = self.decoder_queue.qsize() if (not ArticleCache.do.reserve_space(lines) and qsize > MAX_DECODE_QUEUE) or (qsize > LIMIT_DECODE_QUEUE): sabnzbd.downloader.Downloader.do.delay() def run(self): # First check IPv6 connectivity sabnzbd.EXTERNAL_IPV6 = sabnzbd.test_ipv6() logging.debug('External IPv6 test result: %s', sabnzbd.EXTERNAL_IPV6) # Then have to check the quality of SSL verification if sabnzbd.HAVE_SSL_CONTEXT: try: import ssl ctx = ssl.create_default_context() base_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ssl_sock = ctx.wrap_socket(base_sock, server_hostname=cfg.selftest_host()) ssl_sock.settimeout(2.0) ssl_sock.connect((cfg.selftest_host(), 443)) ssl_sock.close() except: # Seems something is still wrong sabnzbd.set_https_verification(0) sabnzbd.HAVE_SSL_CONTEXT = False logging.debug('SSL verification test: %s', sabnzbd.HAVE_SSL_CONTEXT) # Start decoders for decoder in self.decoder_workers: decoder.start() # Kick BPS-Meter to check quota BPSMeter.do.update() while 1: for server in self.servers: for nw in server.busy_threads[:]: if (nw.nntp and nw.nntp.error_msg) or (nw.timeout and time.time() > nw.timeout): if nw.nntp and nw.nntp.error_msg: self.__reset_nw(nw, "", warn=False) else: self.__reset_nw(nw, "timed out") server.bad_cons += 1 self.maybe_block_server(server) if server.restart: if not server.busy_threads: newid = server.newid server.stop(self.read_fds, self.write_fds) self.servers.remove(server) if newid: self.init_server(None, newid) self.__restart -= 1 sabnzbd.nzbqueue.NzbQueue.do.reset_all_try_lists() # Have to leave this loop, because we removed element break else: # Restart pending, don't add new articles continue if not server.idle_threads or server.restart or self.is_paused() or self.shutdown or self.delayed or self.postproc: continue if not server.active: continue for nw in server.idle_threads[:]: if nw.timeout: if time.time() < nw.timeout: continue else: nw.timeout = None if server.info is None: self.maybe_block_server(server) request_server_info(server) break article = sabnzbd.nzbqueue.NzbQueue.do.get_article(server, self.servers) if not article: break if server.retention and article.nzf.nzo.avg_stamp < time.time() - server.retention: # Let's get rid of all the articles for this server at once logging.info('Job %s too old for %s, moving on', article.nzf.nzo.work_name, server.id) while article: self.decode(article, None, None) article = article.nzf.nzo.get_article(server, self.servers) break server.idle_threads.remove(nw) server.busy_threads.append(nw) nw.article = article if nw.connected: self.__request_article(nw) else: try: logging.info("%s@%s: Initiating connection", nw.thrdnum, server.id) nw.init_connect(self.write_fds) except: logging.error(T('Failed to initialize %s@%s with reason: %s'), nw.thrdnum, server.id, sys.exc_info()[1]) self.__reset_nw(nw, "failed to initialize") # Exit-point if self.shutdown: empty = True for server in self.servers: if server.busy_threads: empty = False break if empty: # Start decoders for decoder in self.decoder_workers: decoder.stop() decoder.join() for server in self.servers: server.stop(self.read_fds, self.write_fds) logging.info("Shutting down") break if self.force_disconnect: for server in self.servers: for nw in server.idle_threads + server.busy_threads: quit = nw.connected and server.active self.__reset_nw(nw, "forcing disconnect", warn=False, wait=False, quit=quit) # Make sure server address resolution is refreshed server.info = None self.force_disconnect = False # => Select readkeys = self.read_fds.keys() writekeys = self.write_fds.keys() if readkeys or writekeys: read, write, error = select.select(readkeys, writekeys, (), 1.0) # Why check so often when so few things happened? if self.can_be_slowed and len(readkeys) >= 8 and len(read) <= 2: time.sleep(0.01) # Need to initialize the check during first 20 seconds if self.can_be_slowed is None or self.can_be_slowed_timer: # Wait for stable speed to start testing if not self.can_be_slowed_timer and BPSMeter.do.get_stable_speed(timespan=10): self.can_be_slowed_timer = time.time() # Check 10 seconds after enabling slowdown if self.can_be_slowed_timer and time.time() > self.can_be_slowed_timer + 10: # Now let's check if it was stable in the last 10 seconds self.can_be_slowed = BPSMeter.do.get_stable_speed(timespan=10) self.can_be_slowed_timer = 0 logging.debug('Downloader-slowdown: %r', self.can_be_slowed) else: read, write, error = ([], [], []) BPSMeter.do.reset() time.sleep(1.0) DOWNLOADER_CV.acquire() while (sabnzbd.nzbqueue.NzbQueue.do.is_empty() or self.is_paused() or self.delayed or self.postproc) and not \ self.shutdown and not self.__restart: DOWNLOADER_CV.wait() DOWNLOADER_CV.release() self.force_disconnect = False for selected in write: nw = self.write_fds[selected] fileno = nw.nntp.sock.fileno() if fileno not in self.read_fds: self.read_fds[fileno] = nw if fileno in self.write_fds: self.write_fds.pop(fileno) if not read: BPSMeter.do.update() continue for selected in read: nw = self.read_fds[selected] article = nw.article server = nw.server if article: nzo = article.nzf.nzo try: bytes, done, skip = nw.recv_chunk() except: bytes, done, skip = (0, False, False) if skip: BPSMeter.do.update() continue if bytes < 1: self.__reset_nw(nw, "server closed connection", warn=False, wait=False) continue else: if self.bandwidth_limit: bps = BPSMeter.do.get_bps() bps += bytes limit = self.bandwidth_limit if bps > limit: while BPSMeter.do.get_bps() > limit: time.sleep(0.05) BPSMeter.do.update() BPSMeter.do.update(server.id, bytes) if nzo: nzo.update_download_stats(BPSMeter.do.get_bps(), server.id, bytes) if not done and nw.status_code != '222': if not nw.connected or nw.status_code == '480': done = False try: nw.finish_connect(nw.status_code) if sabnzbd.LOG_ALL: logging.debug("%s@%s last message -> %s", nw.thrdnum, nw.server.id, nntp_to_msg(nw.data)) nw.clear_data() except NNTPPermanentError, error: # Handle login problems block = False penalty = 0 msg = error.response ecode = msg[:3] display_msg = ' [%s]' % msg logging.debug('Server login problem: %s, %s', ecode, msg) if ecode in ('502', '400', '481', '482') and clues_too_many(msg): # Too many connections: remove this thread and reduce thread-setting for server # Plan to go back to the full number after a penalty timeout if server.active: errormsg = T('Too many connections to server %s') % display_msg if server.errormsg != errormsg: server.errormsg = errormsg logging.warning(T('Too many connections to server %s'), server.id) self.__reset_nw(nw, None, warn=False, destroy=True, quit=True) self.plan_server(server.id, _PENALTY_TOOMANY) server.threads -= 1 elif ecode in ('502', '481', '482') and clues_too_many_ip(msg): # Account sharing? if server.active: errormsg = T('Probable account sharing') + display_msg if server.errormsg != errormsg: server.errormsg = errormsg name = ' (%s)' % server.id logging.warning(T('Probable account sharing') + name) penalty = _PENALTY_SHARE block = True elif ecode in ('481', '482', '381') or (ecode == '502' and clues_login(msg)): # Cannot login, block this server if server.active: errormsg = T('Failed login for server %s') % display_msg if server.errormsg != errormsg: server.errormsg = errormsg logging.error(T('Failed login for server %s'), server.id) penalty = _PENALTY_PERM block = True elif ecode in ('502', '482'): # Cannot connect (other reasons), block this server if server.active: errormsg = T('Cannot connect to server %s [%s]') % ('', display_msg) if server.errormsg != errormsg: server.errormsg = errormsg logging.warning(T('Cannot connect to server %s [%s]'), server.id, msg) if clues_pay(msg): penalty = _PENALTY_PERM else: penalty = _PENALTY_502 block = True elif ecode == '400': # Temp connection problem? if server.active: logging.debug('Unspecified error 400 from server %s', server.id) penalty = _PENALTY_VERYSHORT block = True else: # Unknown error, just keep trying if server.active: errormsg = T('Cannot connect to server %s [%s]') % ('', display_msg) if server.errormsg != errormsg: server.errormsg = errormsg logging.warning(T('Cannot connect to server %s [%s]'), server.id, msg) penalty = _PENALTY_UNKNOWN block = True if block or (penalty and server.optional): if server.active: server.active = False if penalty and (block or server.optional): self.plan_server(server.id, penalty) sabnzbd.nzbqueue.NzbQueue.do.reset_all_try_lists() self.__reset_nw(nw, None, warn=False, quit=True) continue except: logging.error(T('Connecting %s@%s failed, message=%s'), nw.thrdnum, nw.server.id, nntp_to_msg(nw.data)) # No reset-warning needed, above logging is sufficient self.__reset_nw(nw, None, warn=False) if nw.connected: logging.info("Connecting %s@%s finished", nw.thrdnum, nw.server.id) self.__request_article(nw) elif nw.status_code == '223': done = True logging.debug('Article <%s> is present', article.article) elif nw.status_code == '211': done = False logging.debug("group command ok -> %s", nntp_to_msg(nw.data)) nw.group = nw.article.nzf.nzo.group nw.clear_data() self.__request_article(nw) elif nw.status_code in ('411', '423', '430'): done = True logging.debug('Thread %s@%s: Article %s missing (error=%s)', nw.thrdnum, nw.server.id, article.article, nw.status_code) nw.clear_data() elif nw.status_code == '480': if server.active: server.active = False server.errormsg = T('Server %s requires user/password') % '' self.plan_server(server.id, 0) sabnzbd.nzbqueue.NzbQueue.do.reset_all_try_lists() msg = T('Server %s requires user/password') % nw.server.id self.__reset_nw(nw, msg, quit=True) elif nw.status_code == '500': if nzo.precheck: # Assume "STAT" command is not supported server.have_stat = False logging.debug('Server %s does not support STAT', server.id) else: # Assume "BODY" command is not supported server.have_body = False logging.debug('Server %s does not support BODY', server.id) nw.clear_data() self.__request_article(nw) if done: server.bad_cons = 0 # Succesful data, clear "bad" counter server.errormsg = server.warning = '' if sabnzbd.LOG_ALL: logging.debug('Thread %s@%s: %s done', nw.thrdnum, server.id, article.article) self.decode(article, nw.lines, nw.data) nw.soft_reset() server.busy_threads.remove(nw) server.idle_threads.append(nw) def __lookup_nw(self, nw): """ Find the fileno matching the nw, needed for closed connections """ for f in self.read_fds: if self.read_fds[f] == nw: return f for f in self.write_fds: if self.read_fds[f] == nw: return f return None def __reset_nw(self, nw, errormsg, warn=True, wait=True, destroy=False, quit=False): server = nw.server article = nw.article fileno = None if nw.nntp: try: fileno = nw.nntp.sock.fileno() except: fileno = self.__lookup_nw(nw) destroy = True nw.nntp.error_msg = None if warn and errormsg: server.warning = errormsg logging.info('Thread %s@%s: ' + errormsg, nw.thrdnum, server.id) elif errormsg: logging.info('Thread %s@%s: ' + errormsg, nw.thrdnum, server.id) if nw in server.busy_threads: server.busy_threads.remove(nw) if not (destroy or nw in server.idle_threads): server.idle_threads.append(nw) if fileno and fileno in self.write_fds: self.write_fds.pop(fileno) if fileno and fileno in self.read_fds: self.read_fds.pop(fileno) if article: if article.tries > cfg.max_art_tries() and (article.fetcher.optional or not cfg.max_art_opt()): # Too many tries on this server, consider article missing self.decode(article, None, None) else: # Allow all servers to iterate over each nzo/nzf again sabnzbd.nzbqueue.NzbQueue.do.reset_try_lists(article) if destroy: nw.terminate(quit=quit) else: nw.hard_reset(wait, quit=quit) # Empty SSL info, it might change on next connect server.ssl_info = '' def __request_article(self, nw): try: nzo = nw.article.nzf.nzo if nw.server.send_group and nzo.group != nw.group: group = nzo.group if sabnzbd.LOG_ALL: logging.debug('Thread %s@%s: GROUP <%s>', nw.thrdnum, nw.server.id, group) nw.send_group(group) else: if sabnzbd.LOG_ALL: logging.debug('Thread %s@%s: BODY %s', nw.thrdnum, nw.server.id, nw.article.article) nw.body(nzo.precheck) fileno = nw.nntp.sock.fileno() if fileno not in self.read_fds: self.read_fds[fileno] = nw except socket.error, err: logging.info('Looks like server closed connection: %s', err) self.__reset_nw(nw, "server broke off connection", quit=False) except: logging.error(T('Suspect error in downloader')) logging.info("Traceback: ", exc_info=True) self.__reset_nw(nw, "server broke off connection", quit=False) #------------------------------------------------------------------------------ # Timed restart of servers admin. # For each server all planned events are kept in a list. # When the first timer of a server fires, all other existing timers # are neutralized. # Each server has a dictionary entry, consisting of a list of timestamps. @synchronized(TIMER_LOCK) def plan_server(self, server_id, interval): """ Plan the restart of a server in 'interval' minutes """ if cfg.no_penalties() and interval > _PENALTY_SHORT: # Overwrite in case of no_penalties interval = _PENALTY_SHORT logging.debug('Set planned server resume %s in %s mins', server_id, interval) if server_id not in self._timers: self._timers[server_id] = [] stamp = time.time() + 60.0 * interval self._timers[server_id].append(stamp) if interval: sabnzbd.scheduler.plan_server(self.trigger_server, [server_id, stamp], interval) @synchronized(TIMER_LOCK) def trigger_server(self, server_id, timestamp): """ Called by scheduler, start server if timer still valid """ logging.debug('Trigger planned server resume %s', server_id) if server_id in self._timers: if timestamp in self._timers[server_id]: del self._timers[server_id] self.init_server(server_id, server_id) @NzbQueueLocker @synchronized(TIMER_LOCK) def unblock(self, server_id): # Remove timer try: del self._timers[server_id] except KeyError: pass # Activate server if it was inactive for server in self.servers: if server.id == server_id and not server.active: logging.debug('Unblock server %s', server_id) self.init_server(server_id, server_id) break def unblock_all(self): for server_id in self._timers.keys(): self.unblock(server_id) @NzbQueueLocker @synchronized(TIMER_LOCK) def check_timers(self): """ Make sure every server without a non-expired timer is active """ # Clean expired timers now = time.time() kicked = [] for server_id in self._timers.keys(): if not [stamp for stamp in self._timers[server_id] if stamp >= now]: logging.debug('Forcing re-evaluation of server %s', server_id) del self._timers[server_id] self.init_server(server_id, server_id) kicked.append(server_id) # Activate every inactive server without an active timer for server in self.servers: if server.id not in self._timers: if server.id not in kicked and not server.active: logging.debug('Forcing activation of server %s', server.id) self.init_server(server.id, server.id) def update_server(self, oldserver, newserver): self.init_server(oldserver, newserver) @NzbQueueLocker def wakeup(self): """ Just rattle the semaphore """ pass def stop(self): self.shutdown = True notifier.send_notification("SABnzbd", T('Shutting down'), 'startup') def stop(): DOWNLOADER_CV.acquire() try: Downloader.do.stop() finally: DOWNLOADER_CV.notify_all() DOWNLOADER_CV.release() try: Downloader.do.join() except: pass def clues_login(text): """ Check for any "failed login" clues in the response code """ text = text.lower() for clue in ('username', 'password', 'invalid', 'authen', 'access denied'): if clue in text: return True return False def clues_too_many(text): """ Check for any "too many connections" clues in the response code """ text = text.lower() for clue in ('exceed', 'connections', 'too many', 'threads', 'limit'): # Not 'download limit exceeded' error if (clue in text) and ('download' not in text): return True return False def clues_too_many_ip(text): """ Check for any "account sharing" clues in the response code """ text = text.lower() for clue in ('simultaneous ip', 'multiple ip'): if clue in text: return True return False def clues_pay(text): """ Check for messages about payments """ text = text.lower() for clue in ('credits', 'paym', 'expired', 'exceeded'): if clue in text: return True return False SABnzbd-2.3.2/sabnzbd/emailer.py0000644000000000000000000002774413217005257014562 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.emailer - Send notification emails """ import smtplib import os import logging import re import time import glob from sabnzbd.constants import * import sabnzbd from sabnzbd.misc import to_units, split_host, time_format from sabnzbd.encoding import EmailFilter from sabnzbd.notifier import check_cat import sabnzbd.cfg as cfg def errormsg(msg): logging.error(msg) return msg ############################################################################## # EMAIL_SEND ############################################################################## def send(message, email_to, test=None): """ Send message if message non-empty and email-parms are set """ def utf8(p): return p.encode('utf8', 'ignore') # we should not use CFG if we are testing. we should use values # from UI instead. if test: email_server = utf8(test.get('email_server')) email_from = utf8(test.get('email_from')) email_account = utf8(test.get('email_account')) email_pwd = utf8(test.get('email_pwd')) if email_pwd and not email_pwd.replace('*', ''): # If all stars, get stored password instead email_pwd = utf8(cfg.email_pwd()) else: email_server = utf8(cfg.email_server()) email_from = utf8(cfg.email_from()) email_account = utf8(cfg.email_account()) email_pwd = utf8(cfg.email_pwd()) # email_to is replaced at send_with_template, since it can be an array if not message.strip('\n\r\t '): return "Skipped empty message" if email_server and email_to and email_from: message = _prepare_message(message) server, port = split_host(email_server) if not port: port = 25 logging.debug("Connecting to server %s:%s", server, port) try: mailconn = smtplib.SMTP_SSL(server, port) mailconn.ehlo() logging.debug("Connected to server %s:%s", server, port) except Exception, errorcode: if errorcode[0]: # Non SSL mail server logging.debug("Non-SSL mail server detected " "reconnecting to server %s:%s", server, port) try: mailconn = smtplib.SMTP(server, port) mailconn.ehlo() except: return errormsg(T('Failed to connect to mail server')) else: return errormsg(T('Failed to connect to mail server')) # TLS support if mailconn.ehlo_resp: m = re.search('STARTTLS', mailconn.ehlo_resp, re.IGNORECASE) if m: logging.debug("TLS mail server detected") try: mailconn.starttls() mailconn.ehlo() except: return errormsg(T('Failed to initiate TLS connection')) # Authentication if (email_account != "") and (email_pwd != ""): try: mailconn.login(email_account, email_pwd) except smtplib.SMTPHeloError: return errormsg(T("The server didn't reply properly to the helo greeting")) except smtplib.SMTPAuthenticationError: return errormsg(T("Failed to authenticate to mail server")) except smtplib.SMTPException: return errormsg(T("No suitable authentication method was found")) except: return errormsg(T("Unknown authentication failure in mail server")) try: mailconn.sendmail(email_from, email_to, message) msg = None except smtplib.SMTPHeloError: msg = errormsg('The server didn\'t reply properly to the helo greeting.') except smtplib.SMTPRecipientsRefused: msg = errormsg('The server rejected ALL recipients (no mail was sent).') except smtplib.SMTPSenderRefused: msg = errormsg('The server didn\'t accept the from_addr.') except smtplib.SMTPDataError: msg = errormsg('The server replied with an unexpected error code (other than a refusal of a recipient).') except: msg = errormsg(T('Failed to send e-mail')) try: mailconn.close() except: errormsg(T('Failed to close mail connection')) if msg: return msg else: logging.info("Notification e-mail successfully sent") return T('Email succeeded') else: return T('Cannot send, missing required data') def get_email_date(): """ Return un-localized date string for the Date: field """ # Get locale indepedant date/time string: "Sun May 22 20:15:12 2011" day, month, dayno, hms, year = time.asctime(time.gmtime()).split() return '%s, %s %s %s %s +0000' % (day, dayno, month, year, hms) ############################################################################## # email_endjob ############################################################################## from Cheetah.Template import Template def send_with_template(prefix, parm, test=None): """ Send an email using template """ parm['from'] = cfg.email_from() parm['date'] = get_email_date() lst = [] path = cfg.email_dir.get_path() if path and os.path.exists(path): try: lst = glob.glob(os.path.join(path, '%s-*.tmpl' % prefix)) except: logging.error(T('Cannot find email templates in %s'), path) else: path = os.path.join(sabnzbd.DIR_PROG, DEF_EMAIL_TMPL) tpath = os.path.join(path, '%s-%s.tmpl' % (prefix, cfg.language())) if os.path.exists(tpath): lst = [tpath] else: lst = [os.path.join(path, '%s-en.tmpl' % prefix)] sent = False for temp in lst: if os.access(temp, os.R_OK): source = _decode_file(temp) if source: sent = True if test: recipients = [test.get('email_to')] else: recipients = cfg.email_to() if len(recipients): for recipient in recipients: parm['to'] = recipient message = Template(source=source, searchList=[parm], filter=EmailFilter, compilerSettings={'directiveStartToken': ''}) ret = send(message.respond(), recipient, test) del message else: ret = T('No recipients given, no email sent') else: ret = T('Invalid encoding of email template %s') % temp errormsg(ret) if not sent: ret = T('No email templates found') errormsg(ret) return ret def endjob(filename, cat, status, path, bytes, fail_msg, stages, script, script_output, script_ret, test=None): """ Send end-of-job email """ # Is it allowed? if not check_cat('misc', cat, keyword='email') and not test: return None # Translate the stage names tr = sabnzbd.api.Ttemplate if not status and fail_msg: xstages = {tr('stage-fail'): (fail_msg,)} else: xstages = {} for stage in stages: lines = [] for line in stages[stage]: if '\n' in line or '
' in line: lines.extend(line.replace('
', '\n').split('\n')) else: lines.append(line) xstages[tr('stage-' + stage.lower())] = lines parm = {} parm['status'] = status parm['name'] = filename parm['path'] = path parm['msgid'] = '' parm['stages'] = xstages parm['script'] = script parm['script_output'] = script_output parm['script_ret'] = script_ret parm['cat'] = cat parm['size'] = "%sB" % to_units(bytes) parm['end_time'] = time.strftime(time_format('%Y-%m-%d %H:%M:%S'), time.localtime(time.time())).decode(codepage) return send_with_template('email', parm, test) def rss_mail(feed, jobs): """ Send notification email containing list of files """ parm = {'amount': len(jobs), 'feed': feed, 'jobs': jobs} return send_with_template('rss', parm) def badfetch_mail(msg, url): """ Send notification email about failed NZB fetch """ parm = {'url': url, 'msg': msg} return send_with_template('badfetch', parm) ############################################################################## # EMAIL_DISKFULL ############################################################################## def diskfull(): """ Send email about disk full, no templates """ if cfg.email_full(): return send(T('''To: %s From: %s Date: %s Subject: SABnzbd reports Disk Full Hi, SABnzbd has stopped downloading, because the disk is almost full. Please make room and resume SABnzbd manually. ''') % (cfg.email_to.get_string(), cfg.email_from(), get_email_date()), cfg.email_to()) else: return "" ################################################################################ def _decode_file(path): """ Return content of file in Unicode string using encoding as specified in the file. Work-around for dumb handling of decoding by Cheetah. """ fp = open(path, 'r') txt = fp.readline() m = re.search(r'#encoding[:\s]+(\S+)', txt) if m and m.group(1): encoding = m.group(1) else: encoding = 'latin-1' source = fp.read() fp.close() try: return source.decode(encoding) except: return '' ############################################################################## from email.message import Message from email.header import Header from email.encoders import encode_quopri RE_HEADER = re.compile(r'^([^:]+):(.*)') def _prepare_message(txt): """ Apply the proper encoding to all email fields. The body will be Latin-1, the headers will be 'quopri'd when necessary. """ def plain(val): """ Return True when val is plain ASCII """ try: val.decode('ascii') return True except: return False # Use Latin-1 because not all email clients know UTF-8. code = 'ISO-8859-1' msg = Message() payload = [] body = False header = False for line in txt.encode(code, 'replace').split('\n'): if header and not line: body = True if body: payload.append(line) else: m = RE_HEADER.search(line) if m: header = True keyword = m.group(1).strip() value = m.group(2).strip() if plain(value): # Don't encode if not needed, because some email clients # choke when headers like "date" are encoded. msg.add_header(keyword, value) else: header = Header(value, code) msg[keyword] = header msg.set_payload('\n'.join(payload), code) # Check for proper encoding, else call it explicitly if 'Content-Transfer-Encoding' not in msg: encode_quopri(msg) return msg.as_string() SABnzbd-2.3.2/sabnzbd/encoding.py0000644000000000000000000002073613217005257014724 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.encoding - Unicoded filename support """ import locale import string from xml.sax.saxutils import escape from Cheetah.Filters import Filter import sabnzbd gUTF = False def auto_fsys(): global gUTF try: if sabnzbd.DARWIN: gUTF = True else: gUTF = locale.getdefaultlocale()[1].lower().find('utf') >= 0 except: # Incorrect locale implementation, assume the worst gUTF = False def change_fsys(value): global gUTF if not sabnzbd.WIN32 and not sabnzbd.DARWIN: if value == 1: gUTF = False elif value == 2: gUTF = True else: auto_fsys() def platform_encode(p): """ Return Unicode name, if not already Unicode, decode with UTF-8 or latin1 """ if isinstance(p, str): try: return p.decode('utf-8') except: return p.decode(codepage, errors='replace').replace('?', '!') else: return p def yenc_name_fixer(p): """ Return Unicode name of 8bit ASCII string, first try utf-8, then cp1252 """ try: return p.decode('utf-8') except: return p.decode('cp1252', errors='replace').replace('?', '!') def special_fixer(p): """ Return string appropriate for the platform. Also takes care of the situation where a non-Windows/UTF-8 system receives a latin-1 encoded name. """ if p: # Remove \" constructions from incoming headers p = p.replace(r'\"', r'"') if not p or isinstance(p, unicode): return p try: # First see if it isn't just UTF-8 p.decode('utf-8') if sabnzbd.DARWIN and '&#' in p: p = fixup_ff4(p) return p.decode('utf-8') except: # Now assume it's 8bit ASCII return p.decode(codepage) def unicoder(p, force=False): """ Make sure a Unicode string is returned When `force` is True, ignore filesystem encoding """ if isinstance(p, unicode): return p if isinstance(p, str): if gUTF or force: try: return p.decode('utf-8') except: return p.decode(codepage, 'replace') return p.decode(codepage, 'replace') else: return unicode(str(p)) def xml_name(p, keep_escape=False, encoding=None): """ Prepare name for use in HTML/XML contect """ if isinstance(p, unicode): pass elif isinstance(p, str): if sabnzbd.DARWIN or encoding == 'utf-8': p = p.decode('utf-8', 'replace') elif gUTF: p = p.decode('utf-8', 'replace') else: p = p.decode(codepage, 'replace') else: p = str(p) if keep_escape: return p.encode('ascii', 'xmlcharrefreplace') else: return escape(p).encode('ascii', 'xmlcharrefreplace') class LatinFilter(Filter): """ Make sure Cheetah gets only Unicode strings """ def filter(self, val, str=str, **kw): if isinstance(val, unicode): return val elif isinstance(val, basestring): try: if sabnzbd.WIN32: return val.decode(codepage) else: return val.decode('utf-8') except: return val.decode(codepage, 'replace') elif val is None: return u'' else: return unicode(str(val)) class EmailFilter(Filter): """ Make sure Cheetah gets only Unicode strings First try utf-8, then 8bit ASCII """ def filter(self, val, str=str, **kw): if isinstance(val, unicode): return val elif isinstance(val, basestring): try: return val.decode('utf-8') except: return val.decode(codepage, 'replace') elif val is None: return u'' else: return unicode(str(val)) ################################################################################ # # Map CodePage-850 characters to Python's pseudo-Unicode 8bit ASCII # Use to transform 8-bit console output to plain Python strings # For example for unrar and par2 output # TAB_850 = \ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F" \ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F" \ "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF" \ "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF" \ "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF" \ "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF" \ "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF" \ "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF" TAB_LATIN = \ "\xC7\xFC\xE9\xE2\xE4\xE0\xE5\xE7\xEA\xEB\xE8\xEF\xEE\xEC\xC4\xC5" \ "\xC9\xE6\xC6\xF4\xF6\xF2\xFB\xF9\xFF\xD6\xDC\xF8\xA3\xD8\xD7\x83" \ "\xE1\xED\xF3\xFA\xF1\xD1\xAA\xBA\xBF\xAE\xAC\xDB\xBC\xA1\xAB\xBB" \ "\x7E\x7E\x7E\x7E\x7E\xC1\xC2\xC0\xA9\x7E\x7E\x7E\x7E\xA2\xA5\x7E" \ "\x7E\x7E\x7E\x7E\x7E\x7E\xE3\xc3\x7E\x7E\x7E\x7E\x7E\x7E\x7E\xA4" \ "\xF0\xD0\xCA\xCB\xC8\x7E\xCD\xCE\xCF\x7E\x7E\x7E\x7E\xA6\xCC\x7E" \ "\xD3\xDF\xD4\xD2\xF5\xD5\xB5\xFE\xDE\xDA\xDB\xD9\xFD\xDD\xAF\xB4" \ "\xAD\xB1\x5F\xBE\xB6\xA7\xF7\xB8\xB0\xA8\xB7\xB9\xB3\xB2\x7E\xA0" def TRANS(p): """ For Windows: Translate CP850 to Python's Latin-1 and return in Unicode Others: return original string """ if sabnzbd.WIN32: if p: return p.translate(string.maketrans(TAB_850, TAB_LATIN)).decode('cp1252', 'replace') else: # translate() fails on empty or None strings return '' else: return unicoder(p) def fixup_ff4(p): """ Fix incompatibility between CherryPy and Firefox-4 on OSX, where a filename contains &#xx; encodings """ name = [] num = 0 start = amp = False for ch in p: if start: if ch.isdigit(): num += ch elif ch == ';': name.append(unichr(int(num)).encode('utf8')) start = False else: name.append('&#%s%s' % (num, ch)) start = False elif ch == '&': amp = True elif amp: amp = False if ch == '#': start = True num = '' else: name.append('&' + ch) else: name.append(ch) return ''.join(name) _HTML_TABLE = { #'&' : '&', # Not yet, texts need to be cleaned from HTML first #'>' : '>', # Not yet, texts need to be cleaned from HTML first #'<' : '<', # Not yet, texts need to be cleaned from HTML first '"': '"', "'": ''' } def html_escape(txt): """ Replace HTML metacharacters with &-constructs """ # Replacement for inefficient xml.sax.saxutils.escape function if any(ch in txt for ch in _HTML_TABLE): return ''.join((_HTML_TABLE.get(ch, ch) for ch in txt)) else: return txt def deunicode(p): """ Return the correct 8bit ASCII encoding for the platform: Latin-1 for Windows/Posix-non-UTF and UTF-8 for OSX/Posix-UTF """ if isinstance(p, unicode): if gUTF: return p.encode('utf-8') else: return p.encode(codepage, 'replace') elif isinstance(p, basestring): if gUTF: try: p.decode('utf-8') return p except: return p.decode(codepage).encode('utf-8') else: try: return p.decode('utf-8').encode(codepage, 'replace') except: return p else: return str(p) auto_fsys() SABnzbd-2.3.2/sabnzbd/getipaddress.py0000644000000000000000000001031313217005257015602 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.getipaddress """ import socket import sabnzbd import sabnzbd.cfg import multiprocessing.pool import functools # decorator stuff: def timeout(max_timeout): """Timeout decorator, parameter in seconds.""" def timeout_decorator(item): """Wrap the original function.""" @functools.wraps(item) def func_wrapper(*args, **kwargs): """Closure for function.""" pool = multiprocessing.pool.ThreadPool(processes=1) async_result = pool.apply_async(item, args, kwargs) # raises a TimeoutError if execution exceeds max_timeout return async_result.get(max_timeout) return func_wrapper return timeout_decorator @timeout(3.0) def addresslookup(myhost): return socket.getaddrinfo(myhost, 80) @timeout(3.0) def addresslookup4(myhost): return socket.getaddrinfo(myhost, 80, socket.AF_INET) @timeout(3.0) def addresslookup6(myhost): return socket.getaddrinfo(myhost, 80, socket.AF_INET6) def localipv4(): try: s_ipv4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s_ipv4.connect(('1.2.3.4', 80)) # Option: use 100.64.1.1 (IANA-Reserved IPv4 Prefix for Shared Address Space) ipv4 = s_ipv4.getsockname()[0] s_ipv4.close() except: ipv4 = None return ipv4 def publicipv4(): # Because of dual IPv4/IPv6 clients, finding the public ipv4 needs special attention, # meaning forcing IPv4 connections, and not allowing IPv6 connections try: import urllib2 ipv4_found = False # we only want IPv4 resolving, so socket.AF_INET: result = addresslookup4(sabnzbd.cfg.selftest_host()) except: # something very bad: no urllib2, no resolving of selftest_host, no network at all public_ipv4 = None return public_ipv4 # we got one or more IPv4 address(es), so let's connect to them for item in result: selftest_ipv4 = item[4][0] # get next IPv4 address of sabnzbd.cfg.selftest_host() try: # put the selftest_host's IPv4 address into the URL req = urllib2.Request("http://" + selftest_ipv4 + "/") # specify the User-Agent, because certain sites refuse connections with "python urllib2" as User-Agent: req.add_header('User-Agent', 'SABnzbd+/%s' % sabnzbd.version.__version__ ) # specify the Host, because we only provide the IPv4 address in the URL: req.add_header('Host', sabnzbd.cfg.selftest_host()) # get the response public_ipv4 = urllib2.urlopen(req, timeout=2).read() # timeout 2 seconds, in case the website is not accessible # ... check the response is indeed an IPv4 address: socket.inet_aton(public_ipv4) # if we got anything else than a plain IPv4 address, this will raise an exception # if we get here without exception, we're done: ipv4_found = True break except: # the connect OR the inet_aton raised an exception, so: # continue the for loop to try next server IPv4 address pass if not ipv4_found: public_ipv4 = None return public_ipv4 def ipv6(): try: s_ipv6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) s_ipv6.connect(('2001:db8::8080', 80)) # IPv6 prefix for documentation purpose ipv6 = s_ipv6.getsockname()[0] s_ipv6.close() except: ipv6 = None return ipv6 SABnzbd-2.3.2/sabnzbd/interface.py0000644000000000000000000031542513217005257015100 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.interface - webinterface """ import os import time import cherrypy import logging import urllib import json import re import hashlib import ssl from threading import Thread from random import randint from xml.sax.saxutils import escape from sabnzbd.utils.rsslib import RSS, Item import sabnzbd import sabnzbd.rss import sabnzbd.scheduler as scheduler from Cheetah.Template import Template from sabnzbd.misc import real_path, to_units, from_units, \ time_format, long_path, calc_age, same_file, \ cat_to_opts, int_conv, globber, globber_full, remove_all, get_base_url from sabnzbd.newswrapper import GetServerParms from sabnzbd.rating import Rating from sabnzbd.bpsmeter import BPSMeter from sabnzbd.encoding import TRANS, xml_name, LatinFilter, unicoder, special_fixer, \ platform_encode import sabnzbd.config as config import sabnzbd.cfg as cfg import sabnzbd.notifier as notifier import sabnzbd.newsunpack from sabnzbd.downloader import Downloader from sabnzbd.nzbqueue import NzbQueue import sabnzbd.wizard from sabnzbd.utils.servertests import test_nntp_server_dict from sabnzbd.decoder import HAVE_YENC, SABYENC_ENABLED from sabnzbd.utils.diskspeed import diskspeedmeasure from sabnzbd.utils.getperformance import getpystone from sabnzbd.constants import NORMAL_PRIORITY, MEBI, DEF_SKIN_COLORS, DEF_STDINTF, \ DEF_STDCONFIG, DEF_MAIN_TMPL, DEFAULT_PRIORITY from sabnzbd.lang import list_languages, set_language from sabnzbd.api import list_scripts, list_cats, del_from_section, \ api_handler, build_queue, remove_callable, rss_qstatus, build_status, \ retry_job, retry_all_jobs, build_header, build_history, del_job_files, \ format_bytes, std_time, report, del_hist_job, Ttemplate, \ build_queue_header, _api_test_email, _api_test_notif ############################################################################## # Global constants ############################################################################## DIRECTIVES = { 'directiveStartToken': '', 'prioritizeSearchListOverSelf': True } FILTER = LatinFilter def check_server(host, port, ajax): """ Check if server address resolves properly """ if host.lower() == 'localhost' and sabnzbd.AMBI_LOCALHOST: return badParameterResponse(T('Warning: LOCALHOST is ambiguous, use numerical IP-address.'), ajax) if GetServerParms(host, int_conv(port)): return "" else: return badParameterResponse(T('Server address "%s:%s" is not valid.') % (host, port), ajax) def check_access(access_type=4): """ Check if external address is allowed given `access_type` `access_type`: 1=nzb, 2=api, 3=full_api, 4=webui, 5=webui with login for external """ referrer = cherrypy.request.remote.ip # CherryPy will report ::ffff:192.168.0.10 on dual-stack situation # It will always contain that ::ffff: prefix range_ok = not cfg.local_ranges() or bool([1 for r in cfg.local_ranges() if (referrer.startswith(r) or referrer.replace('::ffff:', '').startswith(r))]) allowed = referrer in ('127.0.0.1', '::ffff:127.0.0.1', '::1') or range_ok or access_type <= cfg.inet_exposure() if not allowed: logging.debug('Refused connection to %s', referrer) return allowed def ConvertSpecials(p): """ Convert None to 'None' and 'Default' to '' """ if p is None: p = 'None' elif p.lower() == T('Default').lower(): p = '' return p def Raiser(root='', **kwargs): args = {} for key in kwargs: val = kwargs.get(key) if val: args[key] = val # Add extras if args: root = '%s?%s' % (root, urllib.urlencode(args)) # Optionally add the leading /sabnzbd/ (or what the user set) if not root.startswith(cfg.url_base()): root = cherrypy.request.script_name + root # Send the redirect return cherrypy.HTTPRedirect(root) def queueRaiser(root, kwargs): return Raiser(root, start=kwargs.get('start'), limit=kwargs.get('limit'), search=kwargs.get('search')) def rssRaiser(root, kwargs): return Raiser(root, feed=kwargs.get('feed')) def IsNone(value): """ Return True if either None, 'None' or '' """ return value is None or value == "" or value.lower() == 'none' def Strip(txt): """ Return stripped string, can handle None """ try: return txt.strip() except: return None ############################################################################## # Web login support ############################################################################## def get_users(): users = {} users[cfg.username()] = cfg.password() return users def encrypt_pwd(pwd): return pwd # Create a more unique ID for each instance COOKIE_SECRET = str(randint(1000,100000)*os.getpid()) def set_login_cookie(remove=False, remember_me=False): """ We try to set a cookie as unique as possible to the current user. Based on it's IP and the current process ID of the SAB instance and a random number, so cookies cannot be re-used """ salt = randint(1,1000) cherrypy.response.cookie['login_cookie'] = hashlib.sha1(str(salt) + cherrypy.request.remote.ip + COOKIE_SECRET).hexdigest() cherrypy.response.cookie['login_cookie']['path'] = '/' cherrypy.response.cookie['login_salt'] = salt cherrypy.response.cookie['login_salt']['path'] = '/' # If we want to be remembered if remember_me: cherrypy.response.cookie['login_cookie']['max-age'] = 3600*24*14 cherrypy.response.cookie['login_salt']['max-age'] = 3600*24*14 # To remove if remove: cherrypy.response.cookie['login_cookie']['expires'] = 0 cherrypy.response.cookie['login_salt']['expires'] = 0 else: # Notify about new login notifier.send_notification(T('User logged in'), T('User logged in to the web interface'), 'new_login') def check_login_cookie(): # Do we have everything? if 'login_cookie' not in cherrypy.request.cookie or 'login_salt' not in cherrypy.request.cookie: return False return cherrypy.request.cookie['login_cookie'].value == hashlib.sha1(str(cherrypy.request.cookie['login_salt'].value) + cherrypy.request.remote.ip + COOKIE_SECRET).hexdigest() def check_login(): # Not when no authentication required or basic-auth is on if not cfg.html_login() or not cfg.username() or not cfg.password(): return True # If we show login for external IP, by using access_type=6 we can check if IP match if cfg.inet_exposure() == 5 and check_access(access_type=6): return True # Check the cookie return check_login_cookie() def set_auth(conf): """ Set the authentication for CherryPy """ if cfg.username() and cfg.password() and not cfg.html_login(): conf.update({'tools.basic_auth.on': True, 'tools.basic_auth.realm': 'SABnzbd', 'tools.basic_auth.users': get_users, 'tools.basic_auth.encrypt': encrypt_pwd}) conf.update({'/api': {'tools.basic_auth.on': False}, '%s/api' % cfg.url_base(): {'tools.basic_auth.on': False}, }) else: conf.update({'tools.basic_auth.on': False}) def check_session(kwargs): """ Check session key """ if not check_access(): return u'Access denied' key = kwargs.get('session') if not key: key = kwargs.get('apikey') msg = None if not key: logging.warning(T('Missing Session key')) msg = T('Error: Session Key Required') elif key != cfg.api_key(): logging.warning(T('Error: Session Key Incorrect')) msg = T('Error: Session Key Incorrect') return msg def check_apikey(kwargs, nokey=False): """ Check api key or nzbkey Return None when OK, otherwise an error message """ def log_warning(txt): # Was it proxy forwarded? xff = cherrypy.request.headers.get('X-Forwarded-For') if xff: txt = '%s %s (X-Forwarded-For: %s)>%s' % (txt, cherrypy.request.remote.ip, xff, cherrypy.request.headers.get('User-Agent', '??')) else: txt = '%s %s>%s' % (txt, cherrypy.request.remote.ip, cherrypy.request.headers.get('User-Agent', '??')) logging.warning('%s', txt) output = kwargs.get('output') mode = kwargs.get('mode', '') name = kwargs.get('name', '') callback = kwargs.get('callback') # Lookup required access level req_access = sabnzbd.api.api_level(mode, name) if req_access == 1 and check_access(1): # NZB-only actions pass elif not check_access(req_access): return report(output, 'Access denied') # First check APIKEY, if OK that's sufficient if not (cfg.disable_key() or nokey): key = kwargs.get('apikey') if not key: key = kwargs.get('session') if not key: if cfg.api_warnings(): log_warning(T('API Key missing, please enter the api key from Config->General into your 3rd party program:')) return report(output, 'API Key Required', callback=callback) elif req_access == 1 and key == cfg.nzb_key(): return None elif key == cfg.api_key(): return None else: log_warning(T('API Key incorrect, Use the api key from Config->General in your 3rd party program:')) return report(output, 'API Key Incorrect', callback=callback) # No active APIKEY, check web credentials instead if cfg.username() and cfg.password(): if check_login() or (kwargs.get('ma_username') == cfg.username() and kwargs.get('ma_password') == cfg.password()): pass else: if cfg.api_warnings(): log_warning(T('Authentication missing, please enter username/password from Config->General into your 3rd party program:')) return report(output, 'Missing authentication', callback=callback) return None ############################################################################## class MainPage(object): def __init__(self): self.__root = '/' # Add all sub-pages self.login = LoginPage() self.queue = QueuePage('/queue/') self.history = HistoryPage('/history/') self.status = Status('/status/') self.config = ConfigPage('/config/') self.nzb = NzoPage('/nzb/') self.wizard = sabnzbd.wizard.Wizard('/wizard/') @cherrypy.expose def index(self, **kwargs): if not check_access(): return Protected() if not check_login(): raise NeedLogin() if not cfg.notified_new_skin() and cfg.web_dir() != 'Glitter': logging.warning(T('Try our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.')) if not cfg.notified_new_skin(): cfg.notified_new_skin.set(1) config.save_config() if kwargs.get('skip_wizard') or config.get_servers(): info = build_header() info['scripts'] = list_scripts(default=True) info['script'] = 'Default' info['cat'] = 'Default' info['categories'] = list_cats(True) info['have_rss_defined'] = bool(config.get_rss()) info['have_watched_dir'] = bool(cfg.dirscan_dir()) # Have logout only with HTML and if inet=5, only when we are external info['have_logout'] = cfg.username() and cfg.password() and (cfg.html_login() and (cfg.inet_exposure() < 5 or (cfg.inet_exposure() == 5 and not check_access(access_type=6)))) bytespersec_list = BPSMeter.do.get_bps_list() info['bytespersec_list'] = ','.join([str(bps) for bps in bytespersec_list]) # For Glitter we pre-load the JSON output if 'Glitter' in sabnzbd.WEB_DIR: # Queue queue = build_queue(limit=cfg.queue_limit(), output='json')[0] # History history = {} grand, month, week, day = BPSMeter.do.get_sums() history['total_size'], history['month_size'], history['week_size'], history['day_size'] = \ to_units(grand), to_units(month), to_units(week), to_units(day) history['slots'], fetched_items, history['noofslots'] = build_history(limit=cfg.history_limit(), output='json') # Make sure the JSON works, otherwise leave empty try: info['preload_queue'] = json.dumps({'queue': remove_callable(queue)}) info['preload_history'] = json.dumps({'history': history}) except UnicodeDecodeError: # We use the javascript recognized 'false' info['preload_queue'] = 'false' info['preload_history'] = 'false' template = Template(file=os.path.join(sabnzbd.WEB_DIR, 'main.tmpl'), filter=FILTER, searchList=[info], compilerSettings=DIRECTIVES) return template.respond() else: # Redirect to the setup wizard raise cherrypy.HTTPRedirect('%s/wizard/' % cfg.url_base()) @cherrypy.expose def addFile(self, **kwargs): msg = check_session(kwargs) if msg: return msg nzbfile = kwargs.get('nzbfile') if nzbfile is not None and nzbfile.filename: if nzbfile.value or nzbfile.file: sabnzbd.add_nzbfile(nzbfile, kwargs.get('pp'), kwargs.get('script'), kwargs.get('cat'), kwargs.get('priority', NORMAL_PRIORITY)) raise Raiser(self.__root) @cherrypy.expose def shutdown(self, **kwargs): msg = check_session(kwargs) # Check for PID pid_in = kwargs.get('pid') if pid_in and int(pid_in) != os.getpid(): msg = "Incorrect PID for this instance, remove PID from URL to initiate shutdown." if msg: return msg else: logging.info('Shutdown requested by interface') sabnzbd.halt() cherrypy.engine.exit() sabnzbd.SABSTOP = True return T('SABnzbd shutdown finished') @cherrypy.expose def pause(self, **kwargs): msg = check_session(kwargs) if msg: return msg scheduler.plan_resume(0) Downloader.do.pause() raise Raiser(self.__root) @cherrypy.expose def resume(self, **kwargs): msg = check_session(kwargs) if msg: return msg scheduler.plan_resume(0) sabnzbd.unpause_all() raise Raiser(self.__root) @cherrypy.expose def rss(self, **kwargs): msg = check_apikey(kwargs, nokey=True) if msg: return msg if kwargs.get('mode') == 'history': return rss_history(cherrypy.url(), limit=kwargs.get('limit', 50), search=kwargs.get('search')) elif kwargs.get('mode') == 'queue': return rss_qstatus() elif kwargs.get('mode') == 'warnings': return rss_warnings() @cherrypy.expose def tapi(self, **kwargs): """ Handler for API over http, for template use """ msg = check_apikey(kwargs) if msg: return msg return api_handler(kwargs) @cherrypy.expose def api(self, **kwargs): """ Handler for API over http, with explicit authentication parameters """ if cfg.api_logging(): # Was it proxy forwarded? xff = cherrypy.request.headers.get('X-Forwarded-For') if xff: logging.debug('API-call from %s (X-Forwarded-For: %s) [%s] %s', cherrypy.request.remote.ip, xff, cherrypy.request.headers.get('User-Agent', '??'), kwargs) else: logging.debug('API-call from %s [%s] %s', cherrypy.request.remote.ip, cherrypy.request.headers.get('User-Agent', '??'), kwargs) mode = kwargs.get('mode', '') if isinstance(mode, list): mode = mode[0] kwargs['mode'] = mode name = kwargs.get('name', '') if isinstance(name, list): name = name[0] kwargs['name'] = name if mode not in ('version', 'auth'): msg = check_apikey(kwargs) if msg: return msg return api_handler(kwargs) @cherrypy.expose def scriptlog(self, **kwargs): """ Duplicate of scriptlog of History, needed for some skins """ # No session key check, due to fixed URLs if not check_access(): return Protected() name = kwargs.get('name') if name: history_db = sabnzbd.connect_db() return ShowString(history_db.get_name(name), history_db.get_script_log(name)) else: raise Raiser(self.__root) @cherrypy.expose def retry(self, **kwargs): """ Duplicate of retry of History, needed for some skins """ msg = check_session(kwargs) if msg: return msg job = kwargs.get('job', '') url = kwargs.get('url', '').strip() pp = kwargs.get('pp') cat = kwargs.get('cat') script = kwargs.get('script') if url: sabnzbd.add_url(url, pp, script, cat, nzbname=kwargs.get('nzbname')) del_hist_job(job, del_files=True) raise Raiser(self.__root) @cherrypy.expose def retry_pp(self, **kwargs): # Duplicate of History/retry_pp to please the SMPL skin :( msg = check_session(kwargs) if msg: return msg retry_job(kwargs.get('job'), kwargs.get('nzbfile'), kwargs.get('password')) raise Raiser(self.__root) @cherrypy.expose def robots_txt(self): """ Keep web crawlers out """ cherrypy.response.headers['Content-Type'] = 'text/plain' return 'User-agent: *\nDisallow: /\n' ############################################################################## class LoginPage(object): @cherrypy.expose def index(self, **kwargs): # Base output var info = build_header(sabnzbd.WEB_DIR_CONFIG) info['error'] = '' # Logout? if kwargs.get('logout'): set_login_cookie(remove=True) raise Raiser() # Check if there's even a username/password set if check_login(): raise Raiser(cherrypy.request.script_name + '/') # Was it proxy forwarded? xff = cherrypy.request.headers.get('X-Forwarded-For') # Check login info if kwargs.get('username') == cfg.username() and kwargs.get('password') == cfg.password(): # Save login cookie set_login_cookie(remember_me=kwargs.get('remember_me', False)) # Log the succes if xff: logging.info('Successful login from %s (X-Forwarded-For: %s)', cherrypy.request.remote.ip, xff) else: logging.info('Successful login from %s', cherrypy.request.remote.ip) # Redirect raise Raiser(cherrypy.request.script_name + '/') elif kwargs.get('username') or kwargs.get('password'): info['error'] = T('Authentication failed, check username/password.') # Warn about the potential security problem fail_msg = T('Unsuccessful login attempt from %s') % cherrypy.request.remote.ip if xff: fail_msg = '%s (X-Forwarded-For: %s)' % (fail_msg, xff) logging.warning(fail_msg) # Show login template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'login', 'main.tmpl'), filter=FILTER, searchList=[info], compilerSettings=DIRECTIVES) return template.respond() ############################################################################## class NzoPage(object): def __init__(self, root): self.__root = root self.__cached_selection = {} # None @cherrypy.expose def default(self, *args, **kwargs): # Allowed URL's # /nzb/SABnzbd_nzo_xxxxx/ # /nzb/SABnzbd_nzo_xxxxx/details # /nzb/SABnzbd_nzo_xxxxx/files # /nzb/SABnzbd_nzo_xxxxx/bulk_operation # /nzb/SABnzbd_nzo_xxxxx/save if not check_access(): return Protected() if not check_login(): raise NeedLogin() nzo_id = None for a in args: if a.startswith('SABnzbd_nzo'): nzo_id = a break nzo = NzbQueue.do.get_nzo(nzo_id) if nzo_id and nzo: info, pnfo_list, bytespersec, q_size, bytes_left_previous_page = build_queue_header() # /SABnzbd_nzo_xxxxx/bulk_operation if 'bulk_operation' in args: return self.bulk_operation(nzo_id, kwargs) # /SABnzbd_nzo_xxxxx/details elif 'details' in args: info = self.nzo_details(info, pnfo_list, nzo_id) # /SABnzbd_nzo_xxxxx/files elif 'files' in args: info = self.nzo_files(info, pnfo_list, nzo_id) # /SABnzbd_nzo_xxxxx/save elif 'save' in args: self.save_details(nzo_id, args, kwargs) return # never reached # /SABnzbd_nzo_xxxxx/ else: info = self.nzo_details(info, pnfo_list, nzo_id) info = self.nzo_files(info, pnfo_list, nzo_id) template = Template(file=os.path.join(sabnzbd.WEB_DIR, 'nzo.tmpl'), filter=FILTER, searchList=[info], compilerSettings=DIRECTIVES) return template.respond() else: # Job no longer exists, go to main page raise Raiser(cherrypy.lib.httputil.urljoin(self.__root, '../queue/')) def nzo_details(self, info, pnfo_list, nzo_id): slot = {} n = 0 for pnfo in pnfo_list: if pnfo.nzo_id == nzo_id: nzo = NzbQueue.do.get_nzo(nzo_id) repair = pnfo.repair unpack = pnfo.unpack delete = pnfo.delete unpackopts = sabnzbd.opts_to_pp(repair, unpack, delete) script = pnfo.script if script is None: script = 'None' cat = pnfo.category if not cat: cat = 'None' filename_pw = xml_name(nzo.final_name_pw_clean) filename = xml_name(nzo.final_name) if nzo.password: password = xml_name(nzo.password).replace('"', '"') else: password = '' priority = pnfo.priority slot['nzo_id'] = str(nzo_id) slot['cat'] = cat slot['filename'] = filename_pw slot['filename_clean'] = filename slot['password'] = password or '' slot['script'] = script slot['priority'] = str(priority) slot['unpackopts'] = str(unpackopts) info['index'] = n break n += 1 info['slot'] = slot info['scripts'] = list_scripts() info['categories'] = list_cats() info['noofslots'] = len(pnfo_list) return info def nzo_files(self, info, pnfo_list, nzo_id): active = [] nzo = NzbQueue.do.get_nzo(nzo_id) if nzo: pnfo = nzo.gather_info(full=True) info['nzo_id'] = pnfo.nzo_id info['filename'] = xml_name(pnfo.filename) for nzf in pnfo.active_files: checked = False if nzf.nzf_id in self.__cached_selection and \ self.__cached_selection[nzf.nzf_id] == 'on': checked = True active.append({'filename': xml_name(nzf.filename if nzf.filename else nzf.subject), 'mbleft': "%.2f" % (nzf.bytes_left / MEBI), 'mb': "%.2f" % (nzf.bytes / MEBI), 'size': format_bytes(nzf.bytes), 'sizeleft': format_bytes(nzf.bytes_left), 'nzf_id': nzf.nzf_id, 'age': calc_age(nzf.date), 'checked': checked}) info['active_files'] = active return info def save_details(self, nzo_id, args, kwargs): index = kwargs.get('index', None) name = kwargs.get('name', None) password = kwargs.get('password', None) if password == "": password = None pp = kwargs.get('pp', None) script = kwargs.get('script', None) cat = kwargs.get('cat', None) priority = kwargs.get('priority', None) nzo = NzbQueue.do.get_nzo(nzo_id) if index is not None: NzbQueue.do.switch(nzo_id, index) if name is not None: NzbQueue.do.change_name(nzo_id, special_fixer(name), password) if cat is not None and nzo.cat is not cat and not (nzo.cat == '*' and cat == 'Default'): NzbQueue.do.change_cat(nzo_id, cat, priority) # Category changed, so make sure "Default" attributes aren't set again if script == 'Default': script = None if priority == 'Default': priority = None if pp == 'Default': pp = None if script is not None and nzo.script != script: NzbQueue.do.change_script(nzo_id, script) if pp is not None and nzo.pp != pp: NzbQueue.do.change_opts(nzo_id, pp) if priority is not None and nzo.priority != int(priority): NzbQueue.do.set_priority(nzo_id, priority) raise Raiser(cherrypy.lib.httputil.urljoin(self.__root, '../queue/')) def bulk_operation(self, nzo_id, kwargs): self.__cached_selection = kwargs if kwargs['action_key'] == 'Delete': for key in kwargs: if kwargs[key] == 'on': NzbQueue.do.remove_nzf(nzo_id, key, force_delete=True) elif kwargs['action_key'] in ('Top', 'Up', 'Down', 'Bottom'): nzf_ids = [] for key in kwargs: if kwargs[key] == 'on': nzf_ids.append(key) size = int_conv(kwargs.get('action_size', 1)) if kwargs['action_key'] == 'Top': NzbQueue.do.move_top_bulk(nzo_id, nzf_ids) elif kwargs['action_key'] == 'Up': NzbQueue.do.move_up_bulk(nzo_id, nzf_ids, size) elif kwargs['action_key'] == 'Down': NzbQueue.do.move_down_bulk(nzo_id, nzf_ids, size) elif kwargs['action_key'] == 'Bottom': NzbQueue.do.move_bottom_bulk(nzo_id, nzf_ids) if NzbQueue.do.get_nzo(nzo_id): url = cherrypy.lib.httputil.urljoin(self.__root, nzo_id) else: url = cherrypy.lib.httputil.urljoin(self.__root, '../queue') if url and not url.endswith('/'): url += '/' raise Raiser(url) ############################################################################## class QueuePage(object): def __init__(self, root): self.__root = root @cherrypy.expose def index(self, **kwargs): if not check_access(): return Protected() if not check_login(): raise NeedLogin() start = int_conv(kwargs.get('start')) limit = int_conv(kwargs.get('limit')) search = kwargs.get('search') info, _pnfo_list, _bytespersec = build_queue(start=start, limit=limit, trans=True, search=search) template = Template(file=os.path.join(sabnzbd.WEB_DIR, 'queue.tmpl'), filter=FILTER, searchList=[info], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def delete(self, **kwargs): msg = check_session(kwargs) if msg: return msg uid = kwargs.get('uid') del_files = int_conv(kwargs.get('del_files')) if uid: NzbQueue.do.remove(uid, False, keep_basic=not del_files, del_files=del_files) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def purge(self, **kwargs): msg = check_session(kwargs) if msg: return msg NzbQueue.do.remove_all(kwargs.get('search')) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def change_queue_complete_action(self, **kwargs): """ Action or script to be performed once the queue has been completed Scripts are prefixed with 'script_' """ msg = check_session(kwargs) if msg: return msg action = kwargs.get('action') sabnzbd.change_queue_complete_action(action) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def switch(self, **kwargs): msg = check_session(kwargs) if msg: return msg uid1 = kwargs.get('uid1') uid2 = kwargs.get('uid2') if uid1 and uid2: NzbQueue.do.switch(uid1, uid2) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def change_opts(self, **kwargs): msg = check_session(kwargs) if msg: return msg nzo_id = kwargs.get('nzo_id') pp = kwargs.get('pp', '') if nzo_id and pp and pp.isdigit(): NzbQueue.do.change_opts(nzo_id, int(pp)) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def change_script(self, **kwargs): msg = check_session(kwargs) if msg: return msg nzo_id = kwargs.get('nzo_id') script = kwargs.get('script', '') if nzo_id and script: if script == 'None': script = None NzbQueue.do.change_script(nzo_id, script) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def change_cat(self, **kwargs): msg = check_session(kwargs) if msg: return msg nzo_id = kwargs.get('nzo_id') cat = kwargs.get('cat', '') if nzo_id and cat: if cat == 'None': cat = None NzbQueue.do.change_cat(nzo_id, cat) cat, pp, script, priority = cat_to_opts(cat) NzbQueue.do.change_script(nzo_id, script) NzbQueue.do.change_opts(nzo_id, pp) NzbQueue.do.set_priority(nzo_id, priority) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def shutdown(self, **kwargs): msg = check_session(kwargs) if msg: return msg else: logging.info('Shutdown requested by interface') sabnzbd.halt() cherrypy.engine.exit() sabnzbd.SABSTOP = True return T('SABnzbd shutdown finished') @cherrypy.expose def pause(self, **kwargs): msg = check_session(kwargs) if msg: return msg scheduler.plan_resume(0) Downloader.do.pause() raise queueRaiser(self.__root, kwargs) @cherrypy.expose def resume(self, **kwargs): msg = check_session(kwargs) if msg: return msg scheduler.plan_resume(0) sabnzbd.unpause_all() raise queueRaiser(self.__root, kwargs) @cherrypy.expose def pause_nzo(self, **kwargs): msg = check_session(kwargs) if msg: return msg uid = kwargs.get('uid', '') NzbQueue.do.pause_multiple_nzo(uid.split(',')) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def resume_nzo(self, **kwargs): msg = check_session(kwargs) if msg: return msg uid = kwargs.get('uid', '') NzbQueue.do.resume_multiple_nzo(uid.split(',')) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def set_priority(self, **kwargs): msg = check_session(kwargs) if msg: return msg NzbQueue.do.set_priority(kwargs.get('nzo_id'), kwargs.get('priority')) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def sort_by_avg_age(self, **kwargs): msg = check_session(kwargs) if msg: return msg NzbQueue.do.sort_queue('avg_age', kwargs.get('dir')) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def sort_by_name(self, **kwargs): msg = check_session(kwargs) if msg: return msg NzbQueue.do.sort_queue('name', kwargs.get('dir')) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def sort_by_size(self, **kwargs): msg = check_session(kwargs) if msg: return msg NzbQueue.do.sort_queue('size', kwargs.get('dir')) raise queueRaiser(self.__root, kwargs) ############################################################################## class HistoryPage(object): def __init__(self, root): self.__root = root self.__verbose = False self.__verbose_list = [] self.__failed_only = False @cherrypy.expose def index(self, **kwargs): if not check_access(): return Protected() if not check_login(): raise NeedLogin() start = int_conv(kwargs.get('start')) limit = int_conv(kwargs.get('limit')) search = kwargs.get('search') failed_only = kwargs.get('failed_only') if failed_only is None: failed_only = self.__failed_only history = build_header() history['isverbose'] = self.__verbose history['failed_only'] = failed_only history['rating_enable'] = bool(cfg.rating_enable()) postfix = T('B') # : Abbreviation for bytes, as in GB grand, month, week, day = BPSMeter.do.get_sums() history['total_size'], history['month_size'], history['week_size'], history['day_size'] = \ to_units(grand, postfix=postfix), to_units(month, postfix=postfix), \ to_units(week, postfix=postfix), to_units(day, postfix=postfix) history['lines'], history['fetched'], history['noofslots'] = build_history(limit=limit, start=start, verbose=self.__verbose, verbose_list=self.__verbose_list, search=search, failed_only=failed_only) if search: history['search'] = escape(search) else: history['search'] = '' history['start'] = int_conv(start) history['limit'] = int_conv(limit) history['finish'] = history['start'] + history['limit'] if history['finish'] > history['noofslots']: history['finish'] = history['noofslots'] if not history['finish']: history['finish'] = history['fetched'] history['time_format'] = time_format template = Template(file=os.path.join(sabnzbd.WEB_DIR, 'history.tmpl'), filter=FILTER, searchList=[history], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def purge(self, **kwargs): msg = check_session(kwargs) if msg: return msg history_db = sabnzbd.connect_db() history_db.remove_history() raise queueRaiser(self.__root, kwargs) @cherrypy.expose def delete(self, **kwargs): msg = check_session(kwargs) if msg: return msg job = kwargs.get('job') del_files = int_conv(kwargs.get('del_files')) if job: jobs = job.split(',') for job in jobs: del_hist_job(job, del_files=del_files) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def retry_pp(self, **kwargs): msg = check_session(kwargs) if msg: return msg retry_job(kwargs.get('job'), kwargs.get('nzbfile'), kwargs.get('password')) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def retry_all(self, **kwargs): msg = check_session(kwargs) if msg: return msg retry_all_jobs() raise queueRaiser(self.__root, kwargs) @cherrypy.expose def purge_failed(self, **kwargs): msg = check_session(kwargs) if msg: return msg del_files = bool(int_conv(kwargs.get('del_files'))) history_db = sabnzbd.connect_db() if del_files: del_job_files(history_db.get_failed_paths()) history_db.remove_failed() raise queueRaiser(self.__root, kwargs) @cherrypy.expose def reset(self, **kwargs): msg = check_session(kwargs) if msg: return msg # sabnzbd.reset_byte_counter() raise queueRaiser(self.__root, kwargs) @cherrypy.expose def tog_verbose(self, **kwargs): msg = check_session(kwargs) if msg: return msg jobs = kwargs.get('jobs') if not jobs: self.__verbose = not self.__verbose self.__verbose_list = [] else: if self.__verbose: self.__verbose = False else: jobs = jobs.split(',') for job in jobs: if job in self.__verbose_list: self.__verbose_list.remove(job) else: self.__verbose_list.append(job) raise queueRaiser(self.__root, kwargs) @cherrypy.expose def tog_failed_only(self, **kwargs): msg = check_session(kwargs) if msg: return msg self.__failed_only = not self.__failed_only raise queueRaiser(self.__root, kwargs) @cherrypy.expose def scriptlog(self, **kwargs): """ Duplicate of scriptlog of History, needed for some skins """ # No session key check, due to fixed URLs if not check_access(): return Protected() name = kwargs.get('name') if name: history_db = sabnzbd.connect_db() return ShowString(history_db.get_name(name), history_db.get_script_log(name)) else: raise Raiser(self.__root) @cherrypy.expose def retry(self, **kwargs): msg = check_session(kwargs) if msg: return msg job = kwargs.get('job', '') url = kwargs.get('url', '').strip() pp = kwargs.get('pp') cat = kwargs.get('cat') script = kwargs.get('script') if url: sabnzbd.add_url(url, pp, script, cat, nzbname=kwargs.get('nzbname')) del_hist_job(job, del_files=True) raise Raiser(self.__root) ############################################################################## class ConfigPage(object): def __init__(self, root): self.__root = root self.folders = ConfigFolders('/config/folders/') self.notify = ConfigNotify('/config/notify/') self.general = ConfigGeneral('/config/general/') self.rss = ConfigRss('/config/rss/') self.scheduling = ConfigScheduling('/config/scheduling/') self.server = ConfigServer('/config/server/') self.switches = ConfigSwitches('/config/switches/') self.categories = ConfigCats('/config/categories/') self.sorting = ConfigSorting('/config/sorting/') self.special = ConfigSpecial('/config/special/') @cherrypy.expose def index(self, **kwargs): if not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) conf['configfn'] = config.get_filename() conf['cmdline'] = sabnzbd.CMDLINE conf['build'] = sabnzbd.version.__baseline__[:7] conf['have_unzip'] = bool(sabnzbd.newsunpack.ZIP_COMMAND) conf['have_7zip'] = bool(sabnzbd.newsunpack.SEVEN_COMMAND) conf['have_cryptography'] = bool(sabnzbd.HAVE_CRYPTOGRAPHY) conf['have_yenc'] = HAVE_YENC conf['have_sabyenc'] = SABYENC_ENABLED conf['have_mt_par2'] = sabnzbd.newsunpack.PAR2_MT conf['have_ssl_context'] = sabnzbd.HAVE_SSL_CONTEXT conf['ssl_version'] = ssl.OPENSSL_VERSION new = {} for svr in config.get_servers(): new[svr] = {} conf['servers'] = new conf['folders'] = NzbQueue.do.scan_jobs(all=False, action=False) template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def restart(self, **kwargs): msg = check_session(kwargs) if msg: return msg else: logging.info('Restart requested by interface') # Do the shutdown async to still send goodbye to browser Thread(target=sabnzbd.trigger_restart, kwargs={'timeout': 1}).start() return T(' 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
') @cherrypy.expose def repair(self, **kwargs): msg = check_session(kwargs) if msg: return msg else: logging.info('Queue repair requested by interface') sabnzbd.request_repair() # Do the shutdown async to still send goodbye to browser Thread(target=sabnzbd.trigger_restart, kwargs={'timeout': 1}).start() return T(' 
SABnzbd shutdown finished.
Wait for about 5 second and then click the button below.

Refresh
') @cherrypy.expose def delete(self, **kwargs): msg = check_session(kwargs) if msg: return msg orphan_delete(kwargs) raise Raiser(self.__root) @cherrypy.expose def add(self, **kwargs): msg = check_session(kwargs) if msg: return msg orphan_add(kwargs) raise Raiser(self.__root) def orphan_delete(kwargs): path = kwargs.get('name') if path: path = platform_encode(path) path = os.path.join(long_path(cfg.download_dir.get_path()), path) logging.info('Removing orphaned job %s', path) remove_all(path, recursive=True) def orphan_delete_all(): paths = NzbQueue.do.scan_jobs(all=False, action=False) for path in paths: kwargs = {'name': path} orphan_delete(kwargs) def orphan_add(kwargs): path = kwargs.get('name') if path: path = platform_encode(path) path = os.path.join(long_path(cfg.download_dir.get_path()), path) logging.info('Re-adding orphaned job %s', path) NzbQueue.do.repair_job(path, None, None) def orphan_add_all(): paths = NzbQueue.do.scan_jobs(all=False, action=False) for path in paths: kwargs = {'name': path} orphan_add(kwargs) ############################################################################## LIST_DIRPAGE = ( 'download_dir', 'download_free', 'complete_dir', 'admin_dir', 'nzb_backup_dir', 'dirscan_dir', 'dirscan_speed', 'script_dir', 'email_dir', 'permissions', 'log_dir', 'password_file' ) class ConfigFolders(object): def __init__(self, root): self.__root = root @cherrypy.expose def index(self, **kwargs): if cfg.configlock() or not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) for kw in LIST_DIRPAGE: conf[kw] = config.get_config('misc', kw)() # Temporary fix, problem with build_header conf['restart_req'] = sabnzbd.RESTART_REQ template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config_folders.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def saveDirectories(self, **kwargs): msg = check_session(kwargs) if msg: return msg for kw in LIST_DIRPAGE: value = kwargs.get(kw) if value is not None: value = platform_encode(value) if kw in ('complete_dir', 'dirscan_dir'): msg = config.get_config('misc', kw).set(value, create=True) else: msg = config.get_config('misc', kw).set(value) if msg: # return sabnzbd.api.report('json', error=msg) return badParameterResponse(msg, kwargs.get('ajax')) sabnzbd.check_incomplete_vs_complete() config.save_config() if kwargs.get('ajax'): return sabnzbd.api.report('json') else: raise Raiser(self.__root) ############################################################################## SWITCH_LIST = \ ('par_option', 'top_only', 'ssl_ciphers', 'direct_unpack', 'enable_meta', 'auto_sort', 'propagation_delay', 'auto_disconnect', 'flat_unpack', 'safe_postproc', 'no_dupes', 'replace_spaces', 'replace_dots', 'ignore_samples', 'pause_on_post_processing', 'nice', 'ionice', 'pre_script', 'pause_on_pwrar', 'sfv_check', 'folder_rename', 'load_balancing', 'quota_size', 'quota_day', 'quota_resume', 'quota_period', 'history_retention', 'pre_check', 'max_art_tries', 'fail_hopeless_jobs', 'enable_all_par', 'enable_recursive', 'no_series_dupes', 'series_propercheck', 'script_can_fail', 'new_nzb_on_failure', 'unwanted_extensions', 'action_on_unwanted_extensions', 'sanitize_safe', 'rating_enable', 'rating_api_key', 'rating_filter_enable', 'rating_filter_abort_audio', 'rating_filter_abort_video', 'rating_filter_abort_encrypted', 'rating_filter_abort_encrypted_confirm', 'rating_filter_abort_spam', 'rating_filter_abort_spam_confirm', 'rating_filter_abort_downvoted', 'rating_filter_abort_keywords', 'rating_filter_pause_audio', 'rating_filter_pause_video', 'rating_filter_pause_encrypted', 'rating_filter_pause_encrypted_confirm', 'rating_filter_pause_spam', 'rating_filter_pause_spam_confirm', 'rating_filter_pause_downvoted', 'rating_filter_pause_keywords' ) class ConfigSwitches(object): def __init__(self, root): self.__root = root @cherrypy.expose def index(self, **kwargs): if cfg.configlock() or not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) conf['have_ssl_context'] = sabnzbd.HAVE_SSL_CONTEXT conf['have_nice'] = bool(sabnzbd.newsunpack.NICE_COMMAND) conf['have_ionice'] = bool(sabnzbd.newsunpack.IONICE_COMMAND) conf['cleanup_list'] = cfg.cleanup_list.get_string() for kw in SWITCH_LIST: conf[kw] = config.get_config('misc', kw)() conf['unwanted_extensions'] = cfg.unwanted_extensions.get_string() conf['scripts'] = list_scripts() or ['None'] template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config_switches.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def saveSwitches(self, **kwargs): msg = check_session(kwargs) if msg: return msg for kw in SWITCH_LIST: item = config.get_config('misc', kw) value = platform_encode(kwargs.get(kw)) if kw == 'unwanted_extensions' and value: value = value.lower().replace('.', '') msg = item.set(value) if msg: return badParameterResponse(msg) cleanup_list = kwargs.get('cleanup_list') if cleanup_list and sabnzbd.WIN32: cleanup_list = cleanup_list.lower() cfg.cleanup_list.set(cleanup_list) config.save_config() raise Raiser(self.__root) ############################################################################## SPECIAL_BOOL_LIST = \ ('start_paused', 'no_penalties', 'ignore_wrong_unrar', 'overwrite_files', 'enable_par_cleanup', 'queue_complete_pers', 'api_warnings', 'ampm', 'enable_unrar', 'enable_unzip', 'enable_7zip', 'enable_filejoin', 'enable_tsjoin', 'ignore_unrar_dates', 'debug_log_decoding', 'multipar', 'osx_menu', 'osx_speed', 'win_menu', 'use_pickle', 'allow_incomplete_nzb', 'rss_filenames', 'ipv6_hosting', 'keep_awake', 'empty_postproc', 'html_login', 'wait_for_dfolder', 'max_art_opt', 'warn_empty_nzb', 'enable_bonjour', 'reject_duplicate_files', 'warn_dupl_jobs', 'replace_illegal', 'backup_for_duplicates', 'disable_api_key', 'api_logging', ) SPECIAL_VALUE_LIST = \ ('size_limit', 'folder_max_length', 'fsys_type', 'movie_rename_limit', 'nomedia_marker', 'req_completion_rate', 'wait_ext_drive', 'show_sysload', 'url_base', 'direct_unpack_threads', 'ipv6_servers', 'selftest_host', 'rating_host' ) SPECIAL_LIST_LIST = ('rss_odd_titles', 'quick_check_ext_ignore') class ConfigSpecial(object): def __init__(self, root): self.__root = root @cherrypy.expose def index(self, **kwargs): if cfg.configlock() or not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) conf['nt'] = sabnzbd.WIN32 conf['switches'] = [(kw, config.get_config('misc', kw)(), config.get_config('misc', kw).default()) for kw in SPECIAL_BOOL_LIST] conf['entries'] = [(kw, config.get_config('misc', kw)(), config.get_config('misc', kw).default()) for kw in SPECIAL_VALUE_LIST] conf['entries'].extend([(kw, config.get_config('misc', kw).get_string(), config.get_config('misc', kw).default_string()) for kw in SPECIAL_LIST_LIST]) template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config_special.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def saveSpecial(self, **kwargs): msg = check_session(kwargs) if msg: return msg for kw in SPECIAL_BOOL_LIST + SPECIAL_VALUE_LIST + SPECIAL_LIST_LIST: item = config.get_config('misc', kw) value = kwargs.get(kw) msg = item.set(value) if msg: return badParameterResponse(msg) config.save_config() raise Raiser(self.__root) ############################################################################## GENERAL_LIST = ( 'host', 'port', 'username', 'refresh_rate', 'cache_limit', 'local_ranges', 'inet_exposure', 'enable_https', 'https_port', 'https_cert', 'https_key', 'https_chain', 'enable_https_verification', 'auto_browser', 'check_new_rel' ) class ConfigGeneral(object): def __init__(self, root): self.__root = root @cherrypy.expose def index(self, **kwargs): def ListColors(web_dir): lst = [] web_dir = os.path.join(sabnzbd.DIR_INTERFACES, web_dir) dd = os.path.abspath(web_dir + '/templates/static/stylesheets/colorschemes') if (not dd) or (not os.access(dd, os.R_OK)): return lst for color in globber(dd): col = color.replace('.css', '') lst.append(col) return lst def add_color(skin_dir, color): if skin_dir: if not color: try: color = DEF_SKIN_COLORS[skin_dir.lower()] except KeyError: return skin_dir return '%s - %s' % (skin_dir, color) else: return '' if cfg.configlock() or not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) conf['configfn'] = config.get_filename() # Temporary fix, problem with build_header conf['restart_req'] = sabnzbd.RESTART_REQ conf['have_ssl_context'] = sabnzbd.HAVE_SSL_CONTEXT conf['have_cryptography'] = bool(sabnzbd.HAVE_CRYPTOGRAPHY) wlist = [] interfaces = globber_full(sabnzbd.DIR_INTERFACES) for k in interfaces: if k.endswith(DEF_STDINTF): interfaces.remove(k) interfaces.insert(0, k) break for k in interfaces: if k.endswith(DEF_STDCONFIG): interfaces.remove(k) break for web in interfaces: rweb = os.path.basename(web) if os.access(web + '/' + DEF_MAIN_TMPL, os.R_OK): cols = ListColors(rweb) if cols: for col in cols: wlist.append(add_color(rweb, col)) else: wlist.append(rweb) conf['web_list'] = wlist conf['web_dir'] = add_color(cfg.web_dir(), cfg.web_color()) conf['password'] = cfg.password.get_stars() conf['language'] = cfg.language() lang_list = list_languages() if len(lang_list) < 2: lang_list = [] conf['lang_list'] = lang_list for kw in GENERAL_LIST: conf[kw] = config.get_config('misc', kw)() conf['bandwidth_max'] = cfg.bandwidth_max() conf['bandwidth_perc'] = cfg.bandwidth_perc() conf['nzb_key'] = cfg.nzb_key() conf['local_ranges'] = cfg.local_ranges.get_string() conf['my_lcldata'] = cfg.admin_dir.get_path() conf['caller_url'] = cherrypy.request.base + cfg.url_base() template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config_general.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def saveGeneral(self, **kwargs): msg = check_session(kwargs) if msg: return msg # Handle general options for kw in GENERAL_LIST: item = config.get_config('misc', kw) value = platform_encode(kwargs.get(kw)) msg = item.set(value) if msg: return badParameterResponse(msg) # Handle special options language = kwargs.get('language') if language and language != cfg.language(): cfg.language.set(language) set_language(language) sabnzbd.api.clear_trans_cache() cfg.password.set(kwargs.get('password')) web_dir = kwargs.get('web_dir') change_web_dir(web_dir) bandwidth_max = kwargs.get('bandwidth_max') if bandwidth_max is not None: cfg.bandwidth_max.set(bandwidth_max) bandwidth_perc = kwargs.get('bandwidth_perc') if bandwidth_perc is not None: cfg.bandwidth_perc.set(bandwidth_perc) bandwidth_perc = cfg.bandwidth_perc() if bandwidth_perc and not bandwidth_max: logging.warning(T('You must set a maximum bandwidth before you can set a bandwidth limit')) config.save_config() # Update CherryPy authentication set_auth(cherrypy.config) if kwargs.get('ajax'): return sabnzbd.api.report('json', data={'success': True, 'restart_req': sabnzbd.RESTART_REQ}) else: raise Raiser(self.__root) def change_web_dir(web_dir): try: web_dir, web_color = web_dir.split(' - ') except: try: web_color = DEF_SKIN_COLORS[web_dir.lower()] except: web_color = '' web_dir_path = real_path(sabnzbd.DIR_INTERFACES, web_dir) if not os.path.exists(web_dir_path): return badParameterResponse('Cannot find web template: %s' % unicoder(web_dir_path)) else: cfg.web_dir.set(web_dir) cfg.web_color.set(web_color) ############################################################################## class ConfigServer(object): def __init__(self, root): self.__root = root @cherrypy.expose def index(self, **kwargs): if cfg.configlock() or not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) new = [] servers = config.get_servers() server_names = sorted(servers.keys(), key=lambda svr: '%d%02d%s' % (int(not servers[svr].enable()), servers[svr].priority(), servers[svr].displayname().lower())) for svr in server_names: new.append(servers[svr].get_dict(safe=True)) t, m, w, d, timeline = BPSMeter.do.amounts(svr) if t: new[-1]['amounts'] = to_units(t), to_units(m), to_units(w), to_units(d), timeline conf['servers'] = new conf['cats'] = list_cats(default=True) conf['have_ssl_context'] = sabnzbd.HAVE_SSL_CONTEXT template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config_server.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def addServer(self, **kwargs): return handle_server(kwargs, self.__root, True) @cherrypy.expose def saveServer(self, **kwargs): return handle_server(kwargs, self.__root) @cherrypy.expose def testServer(self, **kwargs): return handle_server_test(kwargs, self.__root) @cherrypy.expose def delServer(self, **kwargs): msg = check_session(kwargs) if msg: return msg kwargs['section'] = 'servers' kwargs['keyword'] = kwargs.get('server') del_from_section(kwargs) raise Raiser(self.__root) @cherrypy.expose def clrServer(self, **kwargs): msg = check_session(kwargs) if msg: return msg server = kwargs.get('server') if server: BPSMeter.do.clear_server(server) raise Raiser(self.__root) @cherrypy.expose def toggleServer(self, **kwargs): msg = check_session(kwargs) if msg: return msg server = kwargs.get('server') if server: svr = config.get_config('servers', server) if svr: svr.enable.set(not svr.enable()) config.save_config() Downloader.do.update_server(server, server) raise Raiser(self.__root) def unique_svr_name(server): """ Return a unique variant on given server name """ num = 0 svr = 1 new_name = server while svr: if num: new_name = '%s@%d' % (server, num) else: new_name = '%s' % server svr = config.get_config('servers', new_name) num += 1 return new_name def handle_server(kwargs, root=None, new_svr=False): """ Internal server handler """ msg = check_session(kwargs) if msg: return msg ajax = kwargs.get('ajax') host = kwargs.get('host', '').strip() if not host: return badParameterResponse(T('Server address required'), ajax) port = kwargs.get('port', '').strip() if not port: if not kwargs.get('ssl', '').strip(): port = '119' else: port = '563' kwargs['port'] = port if kwargs.get('connections', '').strip() == '': kwargs['connections'] = '1' if kwargs.get('enable') == '1': msg = check_server(host, port, ajax) if msg: return msg # Default server name is just the host name server = host svr = None old_server = kwargs.get('server') if old_server: svr = config.get_config('servers', old_server) if svr: server = old_server else: svr = config.get_config('servers', server) if new_svr: server = unique_svr_name(server) for kw in ('ssl', 'send_group', 'enable', 'optional'): if kw not in kwargs.keys(): kwargs[kw] = None if svr and not new_svr: svr.set_dict(kwargs) else: old_server = None config.ConfigServer(server, kwargs) config.save_config() Downloader.do.update_server(old_server, server) if root: if ajax: return sabnzbd.api.report('json') else: raise Raiser(root) def handle_server_test(kwargs, root): _result, msg = test_nntp_server_dict(kwargs) return msg ############################################################################## class ConfigRss(object): def __init__(self, root): self.__root = root self.__refresh_readout = None # Set to URL when new readout is needed self.__refresh_download = False # True when feed needs to be read self.__refresh_force = False # True if forced download of all matches is required self.__refresh_ignore = False # True if first batch of new feed must be ignored self.__evaluate = False # True if feed needs to be re-filtered self.__show_eval_button = False # True if the "Apply filers" button should be shown self.__last_msg = '' # Last error message from RSS reader @cherrypy.expose def index(self, **kwargs): if cfg.configlock() or not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) conf['scripts'] = list_scripts(default=True) pick_script = conf['scripts'] != [] conf['categories'] = list_cats(default=True) pick_cat = conf['categories'] != [] conf['rss_rate'] = cfg.rss_rate() rss = {} feeds = config.get_rss() for feed in feeds: rss[feed] = feeds[feed].get_dict() filters = feeds[feed].filters() rss[feed]['filters'] = filters rss[feed]['filter_states'] = [bool(sabnzbd.rss.convert_filter(f[4])) for f in filters] rss[feed]['filtercount'] = len(filters) rss[feed]['pick_cat'] = pick_cat rss[feed]['pick_script'] = pick_script rss[feed]['link'] = urllib.quote_plus(feed.encode('utf-8')) rss[feed]['baselink'] = [get_base_url(uri) for uri in rss[feed]['uri']] rss[feed]['uris'] = feeds[feed].uri.get_string() active_feed = kwargs.get('feed', '') conf['active_feed'] = active_feed conf['rss'] = rss conf['rss_next'] = time.strftime(time_format('%H:%M'), time.localtime(sabnzbd.rss.next_run())).decode(codepage) if active_feed: readout = bool(self.__refresh_readout) logging.debug('RSS READOUT = %s', readout) if not readout: self.__refresh_download = False self.__refresh_force = False self.__refresh_ignore = False if self.__evaluate: msg = sabnzbd.rss.run_feed(active_feed, download=self.__refresh_download, force=self.__refresh_force, ignoreFirst=self.__refresh_ignore, readout=readout) else: msg = '' self.__evaluate = False if readout: sabnzbd.rss.save() self.__last_msg = msg else: msg = self.__last_msg self.__refresh_readout = None conf['evalButton'] = self.__show_eval_button conf['error'] = msg conf['downloaded'], conf['matched'], conf['unmatched'] = GetRssLog(active_feed) else: self.__last_msg = '' # Find a unique new Feed name unum = 1 txt = T('Feed') # : Used as default Feed name in Config->RSS while txt + str(unum) in feeds: unum += 1 conf['feed'] = txt + str(unum) template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config_rss.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def save_rss_rate(self, **kwargs): """ Save changed RSS automatic readout rate """ msg = check_session(kwargs) if msg: return msg cfg.rss_rate.set(kwargs.get('rss_rate')) config.save_config() scheduler.restart() raise rssRaiser(self.__root, kwargs) @cherrypy.expose def upd_rss_feed(self, **kwargs): """ Update Feed level attributes, legacy version: ignores 'enable' parameter """ msg = check_session(kwargs) if msg: return msg if kwargs.get('enable') is not None: del kwargs['enable'] try: cf = config.get_rss()[kwargs.get('feed')] except KeyError: cf = None uri = Strip(kwargs.get('uri')) if cf and uri: kwargs['uri'] = uri cf.set_dict(kwargs) config.save_config() self.__evaluate = False self.__show_eval_button = True raise rssRaiser(self.__root, kwargs) @cherrypy.expose def save_rss_feed(self, **kwargs): """ Update Feed level attributes """ msg = check_session(kwargs) if msg: return msg try: cf = config.get_rss()[kwargs.get('feed')] except KeyError: cf = None if 'enable' not in kwargs: kwargs['enable'] = 0 uri = Strip(kwargs.get('uri')) if cf and uri: kwargs['uri'] = uri cf.set_dict(kwargs) config.save_config() raise rssRaiser(self.__root, kwargs) @cherrypy.expose def toggle_rss_feed(self, **kwargs): """ Toggle automatic read-out flag of Feed """ msg = check_session(kwargs) if msg: return msg try: item = config.get_rss()[kwargs.get('feed')] except KeyError: item = None if cfg: item.enable.set(not item.enable()) config.save_config() if kwargs.get('table'): raise Raiser(self.__root) else: raise rssRaiser(self.__root, kwargs) @cherrypy.expose def add_rss_feed(self, **kwargs): """ Add one new RSS feed definition """ msg = check_session(kwargs) if msg: return msg feed = Strip(kwargs.get('feed')).strip('[]') uri = Strip(kwargs.get('uri')) if feed and uri: try: cfg = config.get_rss()[feed] except KeyError: cfg = None if (not cfg) and uri: kwargs['feed'] = feed kwargs['uri'] = uri config.ConfigRSS(feed, kwargs) # Clear out any existing reference to this feed name # Otherwise first-run detection can fail sabnzbd.rss.clear_feed(feed) config.save_config() self.__refresh_readout = feed self.__refresh_download = False self.__refresh_force = False self.__refresh_ignore = True self.__evaluate = True raise rssRaiser(self.__root, kwargs) else: raise Raiser(self.__root) else: raise Raiser(self.__root) @cherrypy.expose def upd_rss_filter(self, **kwargs): """ Save updated filter definition """ msg = check_session(kwargs) if msg: return msg try: cfg = config.get_rss()[kwargs.get('feed')] except KeyError: raise rssRaiser(self.__root, kwargs) pp = kwargs.get('pp') if IsNone(pp): pp = '' script = ConvertSpecials(kwargs.get('script')) cat = ConvertSpecials(kwargs.get('cat')) prio = ConvertSpecials(kwargs.get('priority')) filt = kwargs.get('filter_text') enabled = kwargs.get('enabled', '0') if filt: cfg.filters.update(int(kwargs.get('index', 0)), (cat, pp, script, kwargs.get('filter_type'), platform_encode(filt), prio, enabled)) # Move filter if requested index = int_conv(kwargs.get('index', '')) new_index = kwargs.get('new_index', '') if new_index and int_conv(new_index) != index: cfg.filters.move(int(index), int_conv(new_index)) config.save_config() self.__evaluate = False self.__show_eval_button = True raise rssRaiser(self.__root, kwargs) @cherrypy.expose def del_rss_feed(self, *args, **kwargs): """ Remove complete RSS feed """ msg = check_session(kwargs) if msg: return msg kwargs['section'] = 'rss' kwargs['keyword'] = kwargs.get('feed') del_from_section(kwargs) sabnzbd.rss.clear_feed(kwargs.get('feed')) raise Raiser(self.__root) @cherrypy.expose def del_rss_filter(self, **kwargs): """ Remove one RSS filter """ msg = check_session(kwargs) if msg: return msg try: cfg = config.get_rss()[kwargs.get('feed')] except KeyError: raise rssRaiser(self.__root, kwargs) cfg.filters.delete(int(kwargs.get('index', 0))) config.save_config() self.__evaluate = False self.__show_eval_button = True raise rssRaiser(self.__root, kwargs) @cherrypy.expose def download_rss_feed(self, *args, **kwargs): """ Force download of all matching jobs in a feed """ msg = check_session(kwargs) if msg: return msg if 'feed' in kwargs: feed = kwargs['feed'] self.__refresh_readout = feed self.__refresh_download = True self.__refresh_force = True self.__refresh_ignore = False self.__evaluate = True raise rssRaiser(self.__root, kwargs) @cherrypy.expose def clean_rss_jobs(self, *args, **kwargs): """ Remove processed RSS jobs from UI """ msg = check_session(kwargs) if msg: return msg sabnzbd.rss.clear_downloaded(kwargs['feed']) self.__evaluate = True raise rssRaiser(self.__root, kwargs) @cherrypy.expose def test_rss_feed(self, *args, **kwargs): """ Read the feed content again and show results """ msg = check_session(kwargs) if msg: return msg if 'feed' in kwargs: feed = kwargs['feed'] self.__refresh_readout = feed self.__refresh_download = False self.__refresh_force = False self.__refresh_ignore = True self.__evaluate = True self.__show_eval_button = False raise rssRaiser(self.__root, kwargs) @cherrypy.expose def eval_rss_feed(self, *args, **kwargs): """ Re-apply the filters to the feed """ msg = check_session(kwargs) if msg: return msg if 'feed' in kwargs: self.__refresh_download = False self.__refresh_force = False self.__refresh_ignore = False self.__show_eval_button = False self.__evaluate = True raise rssRaiser(self.__root, kwargs) @cherrypy.expose def download(self, **kwargs): """ Download NZB from provider (Download button) """ msg = check_session(kwargs) if msg: return msg feed = kwargs.get('feed') url = kwargs.get('url') nzbname = kwargs.get('nzbname') att = sabnzbd.rss.lookup_url(feed, url) if att: pp = att.get('pp') cat = att.get('cat') script = att.get('script') prio = att.get('prio') if url: sabnzbd.add_url(url, pp, script, cat, prio, nzbname) # Need to pass the title instead sabnzbd.rss.flag_downloaded(feed, url) raise rssRaiser(self.__root, kwargs) @cherrypy.expose def rss_now(self, *args, **kwargs): """ Run an automatic RSS run now """ msg = check_session(kwargs) if msg: return msg scheduler.force_rss() raise rssRaiser(self.__root, kwargs) ############################################################################## _SCHED_ACTIONS = ('resume', 'pause', 'pause_all', 'shutdown', 'restart', 'speedlimit', 'pause_post', 'resume_post', 'scan_folder', 'rss_scan', 'remove_failed', 'remove_completed', 'pause_all_low', 'pause_all_normal', 'pause_all_high', 'resume_all_low', 'resume_all_normal', 'resume_all_high', 'enable_quota', 'disable_quota' ) class ConfigScheduling(object): def __init__(self, root): self.__root = root @cherrypy.expose def index(self, **kwargs): def get_days(): days = {} days["*"] = T('Daily') days["1"] = T('Monday') days["2"] = T('Tuesday') days["3"] = T('Wednesday') days["4"] = T('Thursday') days["5"] = T('Friday') days["6"] = T('Saturday') days["7"] = T('Sunday') return days if cfg.configlock() or not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) actions = [] actions.extend(_SCHED_ACTIONS) day_names = get_days() categories = list_cats(False) snum = 1 conf['schedlines'] = [] conf['taskinfo'] = [] for ev in scheduler.sort_schedules(all_events=False): line = ev[3] conf['schedlines'].append(line) try: enabled, m, h, day_numbers, action = line.split(' ', 4) except: continue action = action.strip() try: action, value = action.split(' ', 1) except: value = '' value = value.strip() if value and not value.lower().strip('0123456789kmgtp%.'): if '%' not in value and from_units(value) < 1.0: value = T('off') # : "Off" value for speedlimit in scheduler else: if '%' not in value and int_conv(value) > 1 and int_conv(value) < 101: value += '%' value = value.upper() if action in actions: action = Ttemplate("sch-" + action) else: if action in ('enable_server', 'disable_server'): try: value = '"%s"' % config.get_servers()[value].displayname() except KeyError: value = '"%s" <<< %s' % (value, T('Undefined server!')) action = Ttemplate("sch-" + action) if action in ('pause_cat', 'resume_cat'): action = Ttemplate("sch-" + action) if value not in categories: # Category name change value = '"%s" <<< %s' % (value, T('Incorrect parameter')) else: value = '"%s"' % value if day_numbers == "1234567": days_of_week = "Daily" elif day_numbers == "12345": days_of_week = "Weekdays" elif day_numbers == "67": days_of_week = "Weekends" else: days_of_week = ", ".join([day_names.get(i, "**") for i in day_numbers]) item = (snum, '%02d' % int(h), '%02d' % int(m), days_of_week, '%s %s' % (action, value), enabled) conf['taskinfo'].append(item) snum += 1 actions_lng = {} for action in actions: actions_lng[action] = Ttemplate("sch-" + action) actions_servers = {} servers = config.get_servers() for srv in servers: actions_servers[srv] = servers[srv].displayname() conf['actions_servers'] = actions_servers conf['actions'] = actions conf['actions_lng'] = actions_lng conf['categories'] = categories template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config_scheduling.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def addSchedule(self, **kwargs): msg = check_session(kwargs) if msg: return msg servers = config.get_servers() categories = list_cats(False) minute = kwargs.get('minute') hour = kwargs.get('hour') days_of_week = ''.join([str(x) for x in kwargs.get('daysofweek', '')]) if not days_of_week: days_of_week = '1234567' action = kwargs.get('action') arguments = kwargs.get('arguments') arguments = arguments.strip().lower() if arguments in ('on', 'enable'): arguments = '1' elif arguments in ('off', 'disable'): arguments = '0' if minute and hour and days_of_week and action: if action == 'speedlimit': if not arguments or arguments.strip('0123456789kmgtp%.'): arguments = 0 elif action in _SCHED_ACTIONS: arguments = '' elif action in servers: if arguments == '1': arguments = action action = 'enable_server' else: arguments = action action = 'disable_server' elif action in ('pause_cat', 'resume_cat'): # Need original category name, not lowercased arguments = arguments.strip() else: # Something else, leave empty action = None if action: sched = cfg.schedules() sched.append('%s %s %s %s %s %s' % (1, minute, hour, days_of_week, action, arguments)) cfg.schedules.set(sched) config.save_config() scheduler.restart(force=True) raise Raiser(self.__root) @cherrypy.expose def delSchedule(self, **kwargs): msg = check_session(kwargs) if msg: return msg schedules = cfg.schedules() line = kwargs.get('line') if line and line in schedules: schedules.remove(line) cfg.schedules.set(schedules) config.save_config() scheduler.restart(force=True) raise Raiser(self.__root) @cherrypy.expose def toggleSchedule(self, **kwargs): msg = check_session(kwargs) if msg: return msg schedules = cfg.schedules() line = kwargs.get('line') if line: for i, schedule in enumerate(schedules): if schedule == line: # Toggle the schedule schedule_split = schedule.split() schedule_split[0] = '%d' % (schedule_split[0] == '0') schedules[i] = ' '.join(schedule_split) break cfg.schedules.set(schedules) config.save_config() scheduler.restart(force=True) raise Raiser(self.__root) ############################################################################## class ConfigCats(object): def __init__(self, root): self.__root = root @cherrypy.expose def index(self, **kwargs): if cfg.configlock() or not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) conf['scripts'] = list_scripts(default=True) conf['defdir'] = cfg.complete_dir.get_path() categories = config.get_ordered_categories() conf['have_cats'] = len(categories) > 1 slotinfo = [] for cat in categories: cat['newzbin'] = cat['newzbin'].replace('"', '"') slotinfo.append(cat) # Add empty line empty = {'name': '', 'order': '0', 'pp': '-1', 'script': '', 'dir': '', 'newzbin': '', 'priority': DEFAULT_PRIORITY} slotinfo.insert(1, empty) conf['slotinfo'] = slotinfo template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config_cat.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def delete(self, **kwargs): msg = check_session(kwargs) if msg: return msg kwargs['section'] = 'categories' kwargs['keyword'] = kwargs.get('name') del_from_section(kwargs) raise Raiser(self.__root) @cherrypy.expose def save(self, **kwargs): msg = check_session(kwargs) if msg: return msg name = kwargs.get('name', '*') if name == '*': newname = name else: newname = re.sub('"', '', kwargs.get('newname', '')) if newname: if kwargs.get('dir'): kwargs['dir'] = platform_encode(kwargs['dir']) # Check if this cat-dir is not sub-folder of incomplete if same_file(cfg.download_dir.get_path(), real_path(cfg.complete_dir.get_path(), kwargs['dir'])): return T('Category folder cannot be a subfolder of the Temporary Download Folder.') # Delete current one and replace with new one if name: config.delete('categories', name) config.ConfigCat(newname.lower(), kwargs) config.save_config() raise Raiser(self.__root) ############################################################################## SORT_LIST = ( 'enable_tv_sorting', 'tv_sort_string', 'tv_categories', 'enable_movie_sorting', 'movie_sort_string', 'movie_sort_extra', 'movie_extra_folder', 'enable_date_sorting', 'date_sort_string', 'movie_categories', 'date_categories' ) class ConfigSorting(object): def __init__(self, root): self.__root = root @cherrypy.expose def index(self, **kwargs): if cfg.configlock() or not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) conf['complete_dir'] = cfg.complete_dir.get_path() for kw in SORT_LIST: conf[kw] = config.get_config('misc', kw)() conf['categories'] = list_cats(False) template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config_sorting.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def saveSorting(self, **kwargs): msg = check_session(kwargs) if msg: return msg try: kwargs['movie_categories'] = kwargs['movie_cat'] except: pass try: kwargs['date_categories'] = kwargs['date_cat'] except: pass try: kwargs['tv_categories'] = kwargs['tv_cat'] except: pass for kw in SORT_LIST: item = config.get_config('misc', kw) value = kwargs.get(kw) msg = item.set(value) if msg: return badParameterResponse(msg) config.save_config() raise Raiser(self.__root) ############################################################################## LOG_API_RE = re.compile(r"(apikey|api)(=|:)[\w]+", re.I) LOG_API_JSON_RE = re.compile(r"u'(apikey|api)': u'[\w]+'", re.I) LOG_USER_RE = re.compile(r"(user|username)\s?=\s?[\S]+", re.I) LOG_PASS_RE = re.compile(r"(password)\s?=\s?[\S]+", re.I) LOG_INI_HIDE_RE = re.compile(r"(email_pwd|email_account|email_to|rating_api_key|pushover_token|pushover_userkey|pushbullet_apikey|prowl_apikey|growl_password|growl_server|IPv[4|6] address)\s?=\s?[\S]+", re.I) LOG_HASH_RE = re.compile(r"([a-fA-F\d]{25})", re.I) class Status(object): def __init__(self, root): self.__root = root @cherrypy.expose def index(self, **kwargs): if not check_access(): return Protected() if not check_login(): raise NeedLogin() header = build_status(skip_dashboard=kwargs.get('skip_dashboard')) template = Template(file=os.path.join(sabnzbd.WEB_DIR, 'status.tmpl'), filter=FILTER, searchList=[header], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def reset_quota(self, **kwargs): msg = check_session(kwargs) if msg: return msg BPSMeter.do.reset_quota(force=True) raise Raiser(self.__root) @cherrypy.expose def disconnect(self, **kwargs): msg = check_session(kwargs) if msg: return msg Downloader.do.disconnect() raise Raiser(self.__root) @cherrypy.expose def refresh_conn(self, **kwargs): msg = check_session(kwargs) if msg: return msg # No real action, just reload the page raise Raiser(self.__root) @cherrypy.expose def showlog(self, **kwargs): msg = check_session(kwargs) if msg: return msg try: sabnzbd.LOGHANDLER.flush() except: pass # Fetch the INI and the log-data and add a message at the top log_data = '--------------------------------\n\n' log_data += 'The log includes a copy of your sabnzbd.ini with\nall usernames, passwords and API-keys removed.' log_data += '\n\n--------------------------------\n' log_data += open(sabnzbd.LOGFILE, "r").read() log_data += open(config.get_filename(), 'r').read() # We need to remove all passwords/usernames/api-keys log_data = LOG_API_RE.sub("apikey=", log_data) log_data = LOG_API_JSON_RE.sub("'apikey':'", log_data) log_data = LOG_USER_RE.sub(r'\g<1>=', log_data) log_data = LOG_PASS_RE.sub("password=", log_data) log_data = LOG_INI_HIDE_RE.sub(r"\1 = ", log_data) log_data = LOG_HASH_RE.sub("", log_data) # Try to replace the username try: import getpass cur_user = getpass.getuser() if cur_user: log_data = log_data.replace(cur_user, '') except: pass # Set headers cherrypy.response.headers['Content-Type'] = 'application/x-download;charset=utf-8' cherrypy.response.headers['Content-Disposition'] = 'attachment;filename="sabnzbd.log"' return log_data @cherrypy.expose def clearwarnings(self, **kwargs): msg = check_session(kwargs) if msg: return msg sabnzbd.GUIHANDLER.clear() raise Raiser(self.__root) @cherrypy.expose def change_loglevel(self, **kwargs): msg = check_session(kwargs) if msg: return msg cfg.log_level.set(kwargs.get('loglevel')) config.save_config() raise Raiser(self.__root) @cherrypy.expose def unblock_server(self, **kwargs): msg = check_session(kwargs) if msg: return msg Downloader.do.unblock(kwargs.get('server')) # Short sleep so that UI shows new server status time.sleep(1.0) raise Raiser(self.__root) @cherrypy.expose def delete(self, **kwargs): msg = check_session(kwargs) if msg: return msg orphan_delete(kwargs) raise Raiser(self.__root) @cherrypy.expose def delete_all(self, **kwargs): msg = check_session(kwargs) if msg: return msg orphan_delete_all() raise Raiser(self.__root) @cherrypy.expose def add(self, **kwargs): msg = check_session(kwargs) if msg: return msg orphan_add(kwargs) raise Raiser(self.__root) @cherrypy.expose def add_all(self, **kwargs): msg = check_session(kwargs) if msg: return msg orphan_add_all() raise Raiser(self.__root) @cherrypy.expose def dashrefresh(self, **kwargs): # This function is run when Refresh button on Dashboard is clicked # Put the time consuming dashboard functions here; they only get executed when the user clicks the Refresh button msg = check_session(kwargs) if msg: return msg # PyStone sabnzbd.PYSTONE_SCORE = getpystone() # Diskspeed sabnzbd.DOWNLOAD_DIR_SPEED = round(diskspeedmeasure(sabnzbd.cfg.download_dir.get_path()), 1) time.sleep(1.0) sabnzbd.COMPLETE_DIR_SPEED = round(diskspeedmeasure(sabnzbd.cfg.complete_dir.get_path()), 1) raise Raiser(self.__root) # Refresh screen def Protected(): cherrypy.response.status = 403 return 'Access denied' def NeedLogin(): raise Raiser('/login/') def badParameterResponse(msg, ajax=None): """ Return a html page with error message and a 'back' button """ if ajax: return sabnzbd.api.report('json', error=msg) else: return ''' SABnzbd %s - %s

%s

%s

''' % (sabnzbd.__version__, T('ERROR:'), T('Incorrect parameter'), unicoder(msg), T('Back')) def ShowString(name, string): """ Return a html page listing a file and a 'back' button """ try: msg = TRANS(string) except: msg = "Encoding Error\n" return ''' %s

%s

%s
''' % (xml_name(name), T('Back'), xml_name(name), escape(unicoder(msg))) def GetRssLog(feed): def make_item(job): # Make a copy job = job.copy() # Now we apply some formatting job['title'] = xml_name(job['title']) job['skip'] = '*' * int(job.get('status', '').endswith('*')) # These fields could be empty job['cat'] = job.get('cat', '') job['size'] = job.get('size', '') # Auto-fetched jobs didn't have these fields set if job.get('url'): job['baselink'] = get_base_url(job.get('url')) if sabnzbd.rss.special_rss_site(job.get('url')): job['nzbname'] = '' else: job['nzbname'] = xml_name(job['title']) else: job['baselink'] = '' job['nzbname'] = xml_name(job['title']) if job.get('size', 0): job['size_units'] = to_units(job['size']) else: job['size_units'] = '-' # And we add extra fields for sorting if job.get('age', 0): job['age_ms'] = time.mktime(job['age'].timetuple()) job['age'] = calc_age(job['age'], True) else: job['age_ms'] = '' job['age'] = '' if job.get('time_downloaded'): job['time_downloaded_ms'] = time.mktime(job['time_downloaded']) job['time_downloaded'] = time.strftime(time_format('%H:%M %a %d %b'), job['time_downloaded']).decode(codepage) else: job['time_downloaded_ms'] = '' job['time_downloaded'] = '' return job jobs = sabnzbd.rss.show_result(feed).values() good, bad, done = ([], [], []) for job in jobs: if job['status'][0] == 'G': good.append(make_item(job)) elif job['status'][0] == 'B': bad.append(make_item(job)) elif job['status'] == 'D': done.append(make_item(job)) try: # Sort based on actual age, in try-catch just to be sure good.sort(key=lambda job: job['age_ms'], reverse=True) bad.sort(key=lambda job: job['age_ms'], reverse=True) done.sort(key=lambda job: job['time_downloaded_ms'], reverse=True) except: # Let the javascript do it then.. pass return done, good, bad ############################################################################## LIST_EMAIL = ( 'email_endjob', 'email_cats', 'email_full', 'email_server', 'email_to', 'email_from', 'email_account', 'email_pwd', 'email_dir', 'email_rss' ) LIST_GROWL = ('growl_enable', 'growl_cats', 'growl_server', 'growl_password', 'growl_prio_startup', 'growl_prio_download', 'growl_prio_pp', 'growl_prio_complete', 'growl_prio_failed', 'growl_prio_disk_full', 'growl_prio_warning', 'growl_prio_error', 'growl_prio_queue_done', 'growl_prio_other', 'growl_prio_new_login') LIST_NCENTER = ('ncenter_enable', 'ncenter_cats', 'ncenter_prio_startup', 'ncenter_prio_download', 'ncenter_prio_pp', 'ncenter_prio_complete', 'ncenter_prio_failed', 'ncenter_prio_disk_full', 'ncenter_prio_warning', 'ncenter_prio_error', 'ncenter_prio_queue_done', 'ncenter_prio_other', 'ncenter_prio_new_login') LIST_ACENTER = ('acenter_enable', 'acenter_cats', 'acenter_prio_startup', 'acenter_prio_download', 'acenter_prio_pp', 'acenter_prio_complete', 'acenter_prio_failed', 'acenter_prio_disk_full', 'acenter_prio_warning', 'acenter_prio_error', 'acenter_prio_queue_done', 'acenter_prio_other', 'acenter_prio_new_login') LIST_NTFOSD = ('ntfosd_enable', 'ntfosd_cats', 'ntfosd_prio_startup', 'ntfosd_prio_download', 'ntfosd_prio_pp', 'ntfosd_prio_complete', 'ntfosd_prio_failed', 'ntfosd_prio_disk_full', 'ntfosd_prio_warning', 'ntfosd_prio_error', 'ntfosd_prio_queue_done', 'ntfosd_prio_other', 'ntfosd_prio_new_login') LIST_PROWL = ('prowl_enable', 'prowl_cats', 'prowl_apikey', 'prowl_prio_startup', 'prowl_prio_download', 'prowl_prio_pp', 'prowl_prio_complete', 'prowl_prio_failed', 'prowl_prio_disk_full', 'prowl_prio_warning', 'prowl_prio_error', 'prowl_prio_queue_done', 'prowl_prio_other', 'prowl_prio_new_login') LIST_PUSHOVER = ('pushover_enable', 'pushover_cats', 'pushover_token', 'pushover_userkey', 'pushover_device', 'pushover_prio_startup', 'pushover_prio_download', 'pushover_prio_pp', 'pushover_prio_complete', 'pushover_prio_failed', 'pushover_prio_disk_full', 'pushover_prio_warning', 'pushover_prio_error', 'pushover_prio_queue_done', 'pushover_prio_other', 'pushover_prio_new_login', 'pushover_emergency_retry', 'pushover_emergency_expire') LIST_PUSHBULLET = ('pushbullet_enable', 'pushbullet_cats', 'pushbullet_apikey', 'pushbullet_device', 'pushbullet_prio_startup', 'pushbullet_prio_download', 'pushbullet_prio_pp', 'pushbullet_prio_complete', 'pushbullet_prio_failed', 'pushbullet_prio_disk_full', 'pushbullet_prio_warning', 'pushbullet_prio_error', 'pushbullet_prio_queue_done', 'pushbullet_prio_other', 'pushbullet_prio_new_login') LIST_NSCRIPT = ('nscript_enable', 'nscript_cats', 'nscript_script', 'nscript_parameters', 'nscript_prio_startup', 'nscript_prio_download', 'nscript_prio_pp', 'nscript_prio_complete', 'nscript_prio_failed', 'nscript_prio_disk_full', 'nscript_prio_warning', 'nscript_prio_error', 'nscript_prio_queue_done', 'nscript_prio_other', 'nscript_prio_new_login') class ConfigNotify(object): def __init__(self, root): self.__root = root self.__lastmail = None @cherrypy.expose def index(self, **kwargs): if cfg.configlock() or not check_access(): return Protected() if not check_login(): raise NeedLogin() conf = build_header(sabnzbd.WEB_DIR_CONFIG) conf['my_home'] = sabnzbd.DIR_HOME conf['categories'] = list_cats(False) conf['lastmail'] = self.__lastmail conf['have_growl'] = True conf['have_ntfosd'] = sabnzbd.notifier.have_ntfosd() conf['have_ncenter'] = sabnzbd.DARWIN and bool(sabnzbd.notifier.ncenter_path()) conf['scripts'] = list_scripts(default=False, none=True) for kw in LIST_EMAIL: conf[kw] = config.get_config('misc', kw).get_string() for kw in LIST_GROWL: try: conf[kw] = config.get_config('growl', kw)() except: logging.debug('MISSING KW=%s', kw) for kw in LIST_PROWL: conf[kw] = config.get_config('prowl', kw)() for kw in LIST_PUSHOVER: conf[kw] = config.get_config('pushover', kw)() for kw in LIST_PUSHBULLET: conf[kw] = config.get_config('pushbullet', kw)() for kw in LIST_NCENTER: conf[kw] = config.get_config('ncenter', kw)() for kw in LIST_ACENTER: conf[kw] = config.get_config('acenter', kw)() for kw in LIST_NTFOSD: conf[kw] = config.get_config('ntfosd', kw)() for kw in LIST_NSCRIPT: conf[kw] = config.get_config('nscript', kw)() conf['notify_keys'] = sabnzbd.constants.NOTIFY_KEYS conf['notify_texts'] = sabnzbd.notifier.NOTIFICATION template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config_notify.tmpl'), filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES) return template.respond() @cherrypy.expose def saveEmail(self, **kwargs): msg = check_session(kwargs) if msg: return msg ajax = kwargs.get('ajax') for kw in LIST_EMAIL: msg = config.get_config('misc', kw).set(platform_encode(kwargs.get(kw))) if msg: return badParameterResponse(T('Incorrect value for %s: %s') % (kw, unicoder(msg)), ajax) for kw in LIST_GROWL: msg = config.get_config('growl', kw).set(platform_encode(kwargs.get(kw))) if msg: return badParameterResponse(T('Incorrect value for %s: %s') % (kw, unicoder(msg)), ajax) for kw in LIST_NCENTER: msg = config.get_config('ncenter', kw).set(platform_encode(kwargs.get(kw))) if msg: return badParameterResponse(T('Incorrect value for %s: %s') % (kw, unicoder(msg)), ajax) for kw in LIST_ACENTER: msg = config.get_config('acenter', kw).set(platform_encode(kwargs.get(kw))) if msg: return badParameterResponse(T('Incorrect value for %s: %s') % (kw, unicoder(msg)), ajax) for kw in LIST_NTFOSD: msg = config.get_config('ntfosd', kw).set(platform_encode(kwargs.get(kw))) if msg: return badParameterResponse(T('Incorrect value for %s: %s') % (kw, unicoder(msg)), ajax) for kw in LIST_PROWL: msg = config.get_config('prowl', kw).set(platform_encode(kwargs.get(kw))) if msg: return badParameterResponse(T('Incorrect value for %s: %s') % (kw, unicoder(msg)), ajax) for kw in LIST_PUSHOVER: msg = config.get_config('pushover', kw).set(platform_encode(kwargs.get(kw))) if msg: return badParameterResponse(T('Incorrect value for %s: %s') % (kw, unicoder(msg)), ajax) for kw in LIST_PUSHBULLET: msg = config.get_config('pushbullet', kw).set(platform_encode(kwargs.get(kw, 0))) if msg: return badParameterResponse(T('Incorrect value for %s: %s') % (kw, unicoder(msg)), ajax) for kw in LIST_NSCRIPT: msg = config.get_config('nscript', kw).set(platform_encode(kwargs.get(kw, 0))) if msg: return badParameterResponse(T('Incorrect value for %s: %s') % (kw, unicoder(msg)), ajax) config.save_config() self.__lastmail = None if ajax: return sabnzbd.api.report('json') else: raise Raiser(self.__root) @cherrypy.expose def testmail(self, **kwargs): msg = check_session(kwargs) if msg: return msg self.__lastmail = _api_test_email(name=None, output=None, kwargs=None) raise Raiser(self.__root) @cherrypy.expose def testnotification(self, **kwargs): msg = check_session(kwargs) if msg: return msg _api_test_notif(name=None, output=None, kwargs=None) raise Raiser(self.__root) def rss_history(url, limit=50, search=None): url = url.replace('rss', '') youngest = None rss = RSS() rss.channel.title = "SABnzbd History" rss.channel.description = "Overview of completed downloads" rss.channel.link = "https://sabnzbd.org/" rss.channel.language = "en" items, _fetched_items, _max_items = build_history(limit=limit, search=search) for history in items: item = Item() item.pubDate = std_time(history['completed']) item.title = history['name'] if not youngest: youngest = history['completed'] elif history['completed'] < youngest: youngest = history['completed'] if history['url_info']: item.link = history['url_info'] else: item.link = url item.guid = history['nzo_id'] stageLine = [] for stage in history['stage_log']: stageLine.append("
Stage %s
" % stage['name']) actions = [] for action in stage['actions']: actions.append("
%s
" % (action)) actions.sort() actions.reverse() for act in actions: stageLine.append(act) stageLine.append("") item.description = ''.join(stageLine) rss.addItem(item) rss.channel.lastBuildDate = std_time(youngest) rss.channel.pubDate = std_time(time.time()) return rss.write() def rss_warnings(): """ Return an RSS feed with last warnings/errors """ rss = RSS() rss.channel.title = "SABnzbd Warnings" rss.channel.description = "Overview of warnings/errors" rss.channel.link = "https://sabnzbd.org/" rss.channel.language = "en" for warn in sabnzbd.GUIHANDLER.content(): item = Item() item.title = warn rss.addItem(item) rss.channel.lastBuildDate = std_time(time.time()) rss.channel.pubDate = rss.channel.lastBuildDate return rss.write() SABnzbd-2.3.2/sabnzbd/lang.py0000644000000000000000000001752613217005257014062 0ustar 00000000000000#!/usr/bin/python -OO # -*- coding: utf-8 -*- # Copyright 2011-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.lang - Language support """ # This module should be the first non-standard import to # be done at the top of the application's main file. # This will ensure that the default language is available # and the special functions are active. # # Required keywords for pygettext.py: -k T -k Ta -k TT # # The following pseudo-builtins are provided. # T() Unicode translation # Ta() Latin-1 translation # Tx() Unicode translation of an expression (not a literal string) # TT() Dummy translation, use to mark table entries for POT scanning import gettext import __builtin__ import glob import os import operator import locale # This module cannot import any application modules!! __all__ = ['set_locale_info', 'set_language', 'list_languages'] _DOMAIN = '' # Holds translation domain _LOCALEDIR = '' # Holds path to the translation base folder CODEPAGE = '1252' def set_locale_info(domain, localedir): """ Setup the domain and localedir for translations """ global _DOMAIN, _LOCALEDIR _DOMAIN = domain _LOCALEDIR = localedir def set_language(language=None): """ Activate language, empty language will set default texts. """ global CODEPAGE if not language: language = '' CODEPAGE = str(LanguageTable.get(language, (0, 0, 0))[2] or 1252) # 'codeset' will determine the output of lgettext lng = gettext.translation(_DOMAIN, _LOCALEDIR, [language], fallback=True, codeset='latin-1') # The unicode flag will make _() return Unicode lng.install(unicode=True, names=['lgettext']) __builtin__.__dict__['T'] = __builtin__.__dict__['_'] # Unicode __builtin__.__dict__['Ta'] = __builtin__.__dict__['_'] # Unicode (Used to Latin-1, compatibility support) __builtin__.__dict__['Tx'] = __builtin__.__dict__['_'] # Dynamic translation (unicode) __builtin__.__dict__['TT'] = lambda x: unicode(x) # Use in text tables def list_languages(): """ Return sorted list of (lang-code, lang-string) pairs, representing the available languages. When any language file is found, the default tuple ('en', 'English') will be included. Otherwise an empty list is returned. """ # Findst find all the MO files. # Each folder should also contain a dummy text file giving the language # Example: # /nl/LC_MESSAGES/SABnzbd.mo # /nl/LC_MESSAGES/Nederlands lst = [] for path in glob.glob(os.path.join(_LOCALEDIR, '*')): if os.path.isdir(path) and not path.endswith('en'): lngname = os.path.basename(path) lng = locale.normalize(lngname) # Example: 'pt_BR.ISO8859-1' lng_short = lng[:lng.find('_')] lng_full = lng[:lng.find('.')] # First try full language string, e.g. 'pt_BR' language = LanguageTable.get(lng_full, (lng_full, lng_full)) if language[0] == lng_full: # Full language string not defined: try short form, e.g. 'pt' language = LanguageTable.get(lng_short, (lng_short, lng_short)) lng = lng_short else: lng = lng_full language = language[1].decode('utf-8') lst.append((lng, language)) if lst: lst.append(('en', 'English')) return sorted(lst, key=operator.itemgetter(1)) else: return lst LanguageTable = { 'aa': ('Afar', 'Afaraf', 0), 'af': ('Afrikaans', 'Afrikaans', 0), 'ak': ('Akan', 'Akan', 0), 'sq': ('Albanian', 'Shqip', 0), 'an': ('Aragonese', 'Aragonés', 0), 'ae': ('Avestan', 'Avesta', 0), 'ay': ('Aymara', 'Aymararu', 0), 'bm': ('Bambara', 'Bamanankan', 0), 'eu': ('Basque', 'Euskara', 0), 'bi': ('Bislama', 'Bislama', 0), 'bs': ('Bosnian', 'Bosanskijezik', 0), 'br': ('Breton', 'Brezhoneg', 0), 'ca': ('Catalan', 'Català', 0), 'ch': ('Chamorro', 'Chamoru', 0), 'kw': ('Cornish', 'Kernewek', 0), 'co': ('Corsican', 'Corsu', 0), 'hr': ('Croatian', 'Hrvatski', 0), 'cs': ('Czech', 'Cesky, ceština', 0), 'da': ('Danish', 'Dansk', 0), 'nl': ('Dutch', 'Nederlands', 0), 'en': ('English', 'English', 0), 'eo': ('Esperanto', 'Esperanto', 0), 'et': ('Estonian', 'Eesti', 0), 'fo': ('Faroese', 'Føroyskt', 0), 'fj': ('Fijian', 'Vosa Vakaviti', 0), 'fi': ('Finnish', 'Suomi', 0), 'fr': ('French', 'Français', 0), 'gl': ('Galician', 'Galego', 0), 'de': ('German', 'Deutsch', 0), 'he': ('Hebrew', 'עִבְרִית‎', 1255), 'hz': ('Herero', 'Otjiherero', 0), 'ho': ('Hiri Motu', 'Hiri Motu', 0), 'hu': ('Hungarian', 'Magyar', 0), 'id': ('Indonesian', 'Bahasa Indonesia', 0), 'ga': ('Irish', 'Gaeilge', 0), 'io': ('Ido', 'Ido', 0), 'is': ('Icelandic', 'Íslenska', 0), 'it': ('Italian', 'Italiano', 0), 'jv': ('Javanese', 'BasaJawa', 0), 'rw': ('Kinyarwanda', 'Ikinyarwanda', 0), 'kg': ('Kongo', 'KiKongo', 0), 'kj': ('Kwanyama', 'Kuanyama', 0), 'la': ('Latin', 'Lingua latina', 0), 'lb': ('Luxembourgish', 'Lëtzebuergesch', 0), 'lg': ('Luganda', 'Luganda', 0), 'li': ('Limburgish', 'Limburgs', 0), 'ln': ('Lingala', 'Lingála', 0), 'lt': ('Lithuanian', 'Lietuviukalba', 0), 'lv': ('Latvian', 'Latviešuvaloda', 0), 'gv': ('Manx', 'Gaelg', 0), 'mg': ('Malagasy', 'Malagasy fiteny', 0), 'mt': ('Maltese', 'Malti', 0), 'nb': ('Norwegian Bokmål', 'Norsk bokmål', 0), 'nn': ('Norwegian Nynorsk', 'Norsk nynorsk', 0), 'no': ('Norwegian', 'Norsk', 0), 'oc': ('Occitan', 'Occitan', 0), 'om': ('Oromo', 'Afaan Oromoo', 0), 'pl': ('Polish', 'Polski', 0), 'pt': ('Portuguese', 'Português', 0), 'pt_BR': ('Portuguese Brazillian', 'Português Brasileiro', 0), 'rm': ('Romansh', 'Rumantsch grischun', 0), 'rn': ('Kirundi', 'kiRundi', 0), 'ro': ('Romanian', 'Româna', 1250), 'sc': ('Sardinian', 'Sardu', 0), 'se': ('Northern Sami', 'Davvisámegiella', 0), 'sm': ('Samoan', 'Gagana fa\'a Samoa', 0), 'gd': ('Gaelic', 'Gàidhlig', 0), 'ru': ('Russian', 'русский язык', 1251), 'sr': ('Serbian', 'српски', 1251), 'sn': ('Shona', 'Chi Shona', 0), 'sk': ('Slovak', 'Slovencina', 0), 'sl': ('Slovene', 'Slovenšcina', 0), 'st': ('Southern Sotho', 'Sesotho', 0), 'es': ('Spanish Castilian', 'Español, castellano', 0), 'su': ('Sundanese', 'Basa Sunda', 0), 'sw': ('Swahili', 'Kiswahili', 0), 'ss': ('Swati', 'SiSwati', 0), 'sv': ('Swedish', 'Svenska', 0), 'tn': ('Tswana', 'Setswana', 0), 'to': ('Tonga (Tonga Islands)', 'faka Tonga', 0), 'tr': ('Turkish', 'Türkçe', 0), 'ts': ('Tsonga', 'Xitsonga', 0), 'tw': ('Twi', 'Twi', 0), 'ty': ('Tahitian', 'Reo Tahiti', 0), 'wa': ('Walloon', 'Walon', 0), 'cy': ('Welsh', 'Cymraeg', 0), 'wo': ('Wolof', 'Wollof', 0), 'fy': ('Western Frisian', 'Frysk', 0), 'xh': ('Xhosa', 'isi Xhosa', 0), 'yo': ('Yoruba', 'Yorùbá', 0), 'zu': ('Zulu', 'isi Zulu', 0), 'zh_CN': ('SimpChinese', '简体中文', 936), } # Setup a safe null-translation set_language() SABnzbd-2.3.2/sabnzbd/misc.py0000644000000000000000000015057113217005257014072 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.misc - misc classes """ import os import sys import logging import urllib import re import ctypes import shutil import threading import subprocess import socket import time import datetime import fnmatch import stat import inspect import urllib2 from urlparse import urlparse import sabnzbd from sabnzbd.decorators import synchronized from sabnzbd.constants import DEFAULT_PRIORITY, FUTURE_Q_FOLDER, JOB_ADMIN, \ GIGI, MEBI, DEF_ARTICLE_CACHE_DEFAULT, DEF_ARTICLE_CACHE_MAX import sabnzbd.config as config import sabnzbd.cfg as cfg from sabnzbd.encoding import unicoder, special_fixer, gUTF TAB_UNITS = ('', 'K', 'M', 'G', 'T', 'P') RE_UNITS = re.compile(r'(\d+\.*\d*)\s*([KMGTP]{0,1})', re.I) RE_VERSION = re.compile(r'(\d+)\.(\d+)\.(\d+)([a-zA-Z]*)(\d*)') RE_IP4 = re.compile(r'inet\s+(addr:\s*){0,1}(\d+\.\d+\.\d+\.\d+)') RE_IP6 = re.compile(r'inet6\s+(addr:\s*){0,1}([0-9a-f:]+)', re.I) # Check if strings are defined for AM and PM HAVE_AMPM = bool(time.strftime('%p', time.localtime())) def time_format(fmt): """ Return time-format string adjusted for 12/24 hour clock setting """ if cfg.ampm() and HAVE_AMPM: return fmt.replace('%H:%M:%S', '%I:%M:%S %p').replace('%H:%M', '%I:%M %p') else: return fmt def calc_age(date, trans=False): """ Calculate the age difference between now and date. Value is returned as either days, hours, or minutes. When 'trans' is True, time symbols will be translated. """ if trans: d = T('d') # : Single letter abbreviation of day h = T('h') # : Single letter abbreviation of hour m = T('m') # : Single letter abbreviation of minute else: d = 'd' h = 'h' m = 'm' try: now = datetime.datetime.now() # age = str(now - date).split(".")[0] #old calc_age # time difference dage = now - date seconds = dage.seconds # only one value should be returned # if it is less than 1 day then it returns in hours, unless it is less than one hour where it returns in minutes if dage.days: age = '%s%s' % (dage.days, d) elif seconds / 3600: age = '%s%s' % (seconds / 3600, h) else: age = '%s%s' % (seconds / 60, m) except: age = "-" return age def monthrange(start, finish): """ Calculate months between 2 dates, used in the Config template """ months = (finish.year - start.year) * 12 + finish.month + 1 for i in xrange(start.month, months): year = (i - 1) / 12 + start.year month = (i - 1) % 12 + 1 yield datetime.date(year, month, 1) def safe_lower(txt): """ Return lowercased string. Return '' for None """ if txt: return txt.lower() else: return '' def safe_fnmatch(f, pattern): """ fnmatch will fail if the pattern contains any of it's key characters, like [, ] or !. """ try: return fnmatch.fnmatch(f, pattern) except re.error: return False def globber(path, pattern=u'*'): """ Return matching base file/folder names in folder `path` """ # Cannot use glob.glob() because it doesn't support Windows long name notation if os.path.exists(path): return [f for f in os.listdir(path) if safe_fnmatch(f, pattern)] return [] def globber_full(path, pattern=u'*'): """ Return matching full file/folder names in folder `path` """ # Cannot use glob.glob() because it doesn't support Windows long name notation if os.path.exists(path): try: return [os.path.join(path, f) for f in os.listdir(path) if safe_fnmatch(f, pattern)] except UnicodeDecodeError: # This happens on Linux when names are incorrectly encoded, retry using a non-Unicode path path = path.encode('utf-8') return [os.path.join(path, f) for f in os.listdir(path) if safe_fnmatch(f, pattern)] return [] def cat_to_opts(cat, pp=None, script=None, priority=None): """ Derive options from category, if options not already defined. Specified options have priority over category-options. If no valid category is given, special category '*' will supply default values """ def_cat = config.get_categories('*') cat = safe_lower(cat) if cat in ('', 'none', 'default'): cat = '*' try: my_cat = config.get_categories()[cat] except KeyError: my_cat = def_cat if pp is None: pp = my_cat.pp() if pp == '': pp = def_cat.pp() if not script: script = my_cat.script() if safe_lower(script) in ('', 'default'): script = def_cat.script() if priority is None or priority == '' or priority == DEFAULT_PRIORITY: priority = my_cat.priority() if priority == DEFAULT_PRIORITY: priority = def_cat.priority() # logging.debug('Cat->Attrib cat=%s pp=%s script=%s prio=%s', cat, pp, script, priority) return cat, pp, script, priority _wildcard_to_regex = { '\\': r'\\', '^': r'\^', '$': r'\$', '.': r'\.', '[': r'\[', ']': r'\]', '(': r'\(', ')': r'\)', '+': r'\+', '?': r'.', '|': r'\|', '{': r'\{', '}': r'\}', '*': r'.*' } def wildcard_to_re(text): """ Convert plain wildcard string (with '*' and '?') to regex. """ return ''.join([_wildcard_to_regex.get(ch, ch) for ch in text]) def cat_convert(cat): """ Convert indexer's category/group-name to user categories. If no match found, but indexer-cat equals user-cat, then return user-cat If no match found, but the indexer-cat starts with the user-cat, return user-cat If no match found, return None """ if cat and cat.lower() != 'none': cats = config.get_ordered_categories() raw_cats = config.get_categories() for ucat in cats: try: # Ordered cat-list has tags only as string indexer = raw_cats[ucat['name']].newzbin() if not isinstance(indexer, list): indexer = [indexer] except: indexer = [] for name in indexer: if re.search('^%s$' % wildcard_to_re(name), cat, re.I): if '.' in name: logging.debug('Convert group "%s" to user-cat "%s"', cat, ucat['name']) else: logging.debug('Convert index site category "%s" to user-cat "%s"', cat, ucat['name']) return ucat['name'] # Try to find full match between user category and indexer category for ucat in cats: if cat.lower() == ucat['name'].lower(): logging.debug('Convert index site category "%s" to user-cat "%s"', cat, ucat['name']) return ucat['name'] # Try to find partial match between user category and indexer category for ucat in cats: if cat.lower().startswith(ucat['name'].lower()): logging.debug('Convert index site category "%s" to user-cat "%s"', cat, ucat['name']) return ucat['name'] return None ############################################################################## # sanitize_filename ############################################################################## _DEVICES = ('con', 'prn', 'aux', 'nul', 'com1', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9', 'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9') def replace_win_devices(name): ''' Remove reserved Windows device names from a name. aux.txt ==> _aux.txt txt.aux ==> txt.aux ''' if name: lname = name.lower() for dev in _DEVICES: if lname == dev or lname.startswith(dev + '.'): name = '_' + name break # Remove special NTFS filename if lname.startswith('$mft'): name = name.replace('$', 'S', 1) return name def has_win_device(p): """ Return True if filename part contains forbidden name Before and after sanitizing """ p = os.path.split(p)[1].lower() for dev in _DEVICES: if p == dev or p.startswith(dev + '.') or p.startswith('_' + dev + '.'): return True return False if sabnzbd.WIN32: # the colon should be here too, but we'll handle that separately CH_ILLEGAL = '\/<>?*|"\t' CH_LEGAL = '++{}!@#`+' else: CH_ILLEGAL = '/' CH_LEGAL = '+' def sanitize_filename(name): """ Return filename with illegal chars converted to legal ones and with the par2 extension always in lowercase """ if not name: return name illegal = CH_ILLEGAL legal = CH_LEGAL if ':' in name: if sabnzbd.WIN32: # Compensate for the odd way par2 on Windows substitutes a colon character name = name.replace(':', '3A') elif sabnzbd.DARWIN: # Compensate for the foolish way par2 on OSX handles a colon character name = name[name.rfind(':') + 1:] if sabnzbd.WIN32 or cfg.sanitize_safe(): name = replace_win_devices(name) lst = [] for ch in name.strip(): if ch in illegal: ch = legal[illegal.find(ch)] lst.append(ch) name = ''.join(lst) if not name: name = 'unknown' name, ext = os.path.splitext(name) lowext = ext.lower() if lowext == '.par2' and lowext != ext: ext = lowext return name + ext def sanitize_foldername(name, limit=True): """ Return foldername with dodgy chars converted to safe ones Remove any leading and trailing dot and space characters """ if not name: return name FL_ILLEGAL = CH_ILLEGAL + ':\x92"' FL_LEGAL = CH_LEGAL + "-''" uFL_ILLEGAL = FL_ILLEGAL.decode('cp1252') uFL_LEGAL = FL_LEGAL.decode('cp1252') if isinstance(name, unicode): illegal = uFL_ILLEGAL legal = uFL_LEGAL else: illegal = FL_ILLEGAL legal = FL_LEGAL if cfg.sanitize_safe(): # Remove all bad Windows chars too illegal += r'\/<>?*|":' legal += r'++{}!@#`;' repl = cfg.replace_illegal() lst = [] for ch in name.strip(): if ch in illegal: if repl: ch = legal[illegal.find(ch)] lst.append(ch) else: lst.append(ch) name = ''.join(lst) name = name.strip() if sabnzbd.WIN32 or cfg.sanitize_safe(): name = replace_win_devices(name) maxlen = cfg.folder_max_length() if limit and len(name) > maxlen: name = name[:maxlen] # And finally, make sure it doesn't end in a dot if name != '.' and name != '..': name = name.rstrip('.') if not name: name = 'unknown' return name def sanitize_and_trim_path(path): """ Remove illegal characters and trim element size """ path = path.strip() new_path = '' if sabnzbd.WIN32: if path.startswith(u'\\\\?\\UNC\\'): new_path = u'\\\\?\\UNC\\' path = path[8:] elif path.startswith(u'\\\\?\\'): new_path = u'\\\\?\\' path = path[4:] path = path.replace('\\', '/') parts = path.split('/') if sabnzbd.WIN32 and len(parts[0]) == 2 and ':' in parts[0]: new_path += parts[0] + '/' parts.pop(0) elif path.startswith('//'): new_path = '//' elif path.startswith('/'): new_path = '/' for part in parts: new_path = os.path.join(new_path, sanitize_foldername(part)) return os.path.abspath(os.path.normpath(new_path)) def sanitize_files_in_folder(folder): """ Sanitize each file in the folder, return list of new names """ lst = [] for root, _, files in os.walk(folder): for file_ in files: path = os.path.join(root, file_) new_path = os.path.join(root, sanitize_filename(file_)) if path != new_path: try: os.rename(path, new_path) path = new_path except: logging.debug('Cannot rename %s to %s', path, new_path) lst.append(path) return lst def is_obfuscated_filename(filename): """ Check if this file has an extension, if not, it's probably obfuscated and we don't use it """ return (os.path.splitext(filename)[1] == '') ############################################################################## # DirPermissions ############################################################################## def create_all_dirs(path, umask=False): """ Create all required path elements and set umask on all Return True if last element could be made or exists """ result = True if sabnzbd.WIN32: try: os.makedirs(path) except: result = False else: lst = [] lst.extend(path.split('/')) path = '' for d in lst: if d: path += '/' + d if not os.path.exists(path): try: os.mkdir(path) result = True except: result = False if umask: mask = cfg.umask() if mask: try: os.chmod(path, int(mask, 8) | 0700) except: pass return result ############################################################################## # Real_Path ############################################################################## def real_path(loc, path): """ When 'path' is relative, return normalized join of 'loc' and 'path' When 'path' is absolute, return normalized path A path starting with ~ will be located in the user's Home folder """ # The Windows part is a bit convoluted because # os.path.join() doesn't behave the same for all Python versions if path: path = path.strip() else: path = '' if path: if not sabnzbd.WIN32 and path.startswith('~/'): path = path.replace('~', os.environ.get('HOME', sabnzbd.DIR_HOME), 1) if sabnzbd.WIN32: path = path.replace('/', '\\') if len(path) > 1 and path[0].isalpha() and path[1] == ':': if len(path) == 2 or path[2] != '\\': path = path.replace(':', ':\\', 1) elif path.startswith('\\\\'): pass elif path.startswith('\\'): if len(loc) > 1 and loc[0].isalpha() and loc[1] == ':': path = loc[:2] + path else: path = os.path.join(loc, path) elif path[0] != '/': path = os.path.join(loc, path) else: path = loc return os.path.normpath(os.path.abspath(path)) ############################################################################## # Create_Real_Path ############################################################################## def create_real_path(name, loc, path, umask=False, writable=True): """ When 'path' is relative, create join of 'loc' and 'path' When 'path' is absolute, create normalized path 'name' is used for logging. Optional 'umask' will be applied. 'writable' means that an existing folder should be writable Returns ('success', 'full path') """ if path: my_dir = real_path(loc, path) if not os.path.exists(my_dir): logging.info('%s directory: %s does not exist, try to create it', name, my_dir) if not create_all_dirs(my_dir, umask): logging.error(T('Cannot create directory %s'), clip_path(my_dir)) return (False, my_dir) checks = (os.W_OK + os.R_OK) if writable else os.R_OK if os.access(my_dir, checks): return (True, my_dir) else: logging.error(T('%s directory: %s error accessing'), name, clip_path(my_dir)) return (False, my_dir) else: return (False, "") def is_relative_path(p): """ Return True if path is relative """ p = p.replace('\\', '/') if p and p[0] == '/': return False if sabnzbd.WIN32 and p and len(p) > 2: if p[0].isalpha() and p[1] == ':' and p[2] == '/': return False return True def windows_variant(): """ Determine Windows variant Return vista_plus, x64 """ from win32api import GetVersionEx from win32con import VER_PLATFORM_WIN32_NT import _winreg vista_plus = x64 = False maj, _minor, _buildno, plat, _csd = GetVersionEx() if plat == VER_PLATFORM_WIN32_NT: vista_plus = maj > 5 if vista_plus: # Must be done the hard way, because the Python runtime lies to us. # This does *not* work: # return os.environ['PROCESSOR_ARCHITECTURE'] == 'AMD64' # because the Python runtime returns 'X86' even on an x64 system! key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment") for n in xrange(_winreg.QueryInfoKey(key)[1]): name, value, _val_type = _winreg.EnumValue(key, n) if name == 'PROCESSOR_ARCHITECTURE': x64 = value.upper() == u'AMD64' break _winreg.CloseKey(key) return vista_plus, x64 _SERVICE_KEY = 'SYSTEM\\CurrentControlSet\\services\\' _SERVICE_PARM = 'CommandLine' def get_serv_parms(service): """ Get the service command line parameters from Registry """ import _winreg value = [] try: key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, _SERVICE_KEY + service) for n in xrange(_winreg.QueryInfoKey(key)[1]): name, value, _val_type = _winreg.EnumValue(key, n) if name == _SERVICE_PARM: break _winreg.CloseKey(key) except WindowsError: pass for n in xrange(len(value)): value[n] = value[n] return value def set_serv_parms(service, args): """ Set the service command line parameters in Registry """ import _winreg uargs = [] for arg in args: uargs.append(unicoder(arg)) try: key = _winreg.CreateKey(_winreg.HKEY_LOCAL_MACHINE, _SERVICE_KEY + service) _winreg.SetValueEx(key, _SERVICE_PARM, None, _winreg.REG_MULTI_SZ, uargs) _winreg.CloseKey(key) except WindowsError: return False return True def convert_version(text): """ Convert version string to numerical value and a testversion indicator """ version = 0 test = True m = RE_VERSION.search(text) if m: version = int(m.group(1)) * 1000000 + int(m.group(2)) * 10000 + int(m.group(3)) * 100 try: if m.group(4).lower() == 'rc': version = version + 80 elif m.group(4).lower() == 'beta': version = version + 40 version = version + int(m.group(5)) except: version = version + 99 test = False return version, test def check_latest_version(): """ Do an online check for the latest version Perform an online version check Syntax of online version file: The latter two lines are only present when an alpha/beta/rc is available. Formula for the version numbers (line 1 and 3). ..[rc|beta|alpha] The value for a final version is assumned to be 99. The value for the beta/rc version is 1..98, with RC getting a boost of 80 and Beta of 40. This is done to signal alpha/beta/rc users of availability of the final version (which is implicitly 99). People will only be informed to upgrade to a higher alpha/beta/rc version, if they are already using an alpha/beta/rc. RC's are valued higher than Beta's, which are valued higher than Alpha's. """ if not cfg.version_check(): return current, testver = convert_version(sabnzbd.__version__) if not current: logging.debug("Unsupported release number (%s), will not check", sabnzbd.__version__) return # Using catch-all except's is poor coding practice. # However, the last thing you want is the app crashing due # to bad file content. try: fn = urllib.urlretrieve('https://raw.githubusercontent.com/sabnzbd/sabnzbd.github.io/master/latest.txt')[0] f = open(fn, 'r') data = f.read() f.close() os.remove(fn) except: logging.info('Cannot retrieve version information from GitHub.com') logging.debug('Traceback: ', exc_info=True) return try: latest_label = data.split()[0] except: latest_label = '' try: url = data.split()[1] except: url = '' try: latest_testlabel = data.split()[2] except: latest_testlabel = '' try: url_beta = data.split()[3] except: url_beta = url latest = convert_version(latest_label)[0] latest_test = convert_version(latest_testlabel)[0] logging.debug('Checked for a new release, cur= %s, latest= %s (on %s), latest_test= %s (on %s)', current, latest, url, latest_test, url_beta) if latest_test and cfg.version_check() > 1: # User always wants to see the latest test release latest = latest_test latest_label = latest_testlabel url = url_beta if testver and current < latest: # This is a test version, but user has't seen the # "Final" of this one yet, so show the Final sabnzbd.NEW_VERSION = (latest_label, url) elif current < latest: # This one is behind, show latest final sabnzbd.NEW_VERSION = (latest_label, url) elif testver and current < latest_test: # This is a test version beyond the latest Final, so show latest Alpha/Beta/RC sabnzbd.NEW_VERSION = (latest_testlabel, url_beta) def from_units(val): """ Convert K/M/G/T/P notation to float """ val = str(val).strip().upper() if val == "-1": return val m = RE_UNITS.search(val) if m: if m.group(2): val = float(m.group(1)) unit = m.group(2) n = 0 while unit != TAB_UNITS[n]: val = val * 1024.0 n = n + 1 else: val = m.group(1) try: return float(val) except: return 0.0 else: return 0.0 def to_units(val, spaces=0, postfix=''): """ Convert number to K/M/G/T/P notation Add "spaces" if not ending in letter Show single decimal for M and higher """ dec_limit = 1 decimals = 0 if val < 0: sign = '-' else: sign = '' val = str(abs(val)).strip() n = 0 try: val = float(val) except: return '' while (val > 1023.0) and (n < 5): val = val / 1024.0 n = n + 1 unit = TAB_UNITS[n] if not unit: unit = ' ' * spaces if n > dec_limit: decimals = 1 else: decimals = 0 fmt = '%%s%%.%sf %%s%%s' % decimals return fmt % (sign, val, unit, postfix) def caller_name(skip=2): """Get a name of a caller in the format module.method Originally used: https://gist.github.com/techtonik/2151727 Adapted for speed by using sys calls directly """ # Only do the tracing on Debug (function is always called) if cfg.log_level() != 2: return 'N/A' parentframe = sys._getframe(skip) function_name = parentframe.f_code.co_name # Modulename not available in the binaries, we can use the filename instead if getattr(sys, 'frozen', None): module_name = inspect.getfile(parentframe) else: module_name = inspect.getmodule(parentframe).__name__ # For decorated functions we have to go deeper if function_name in ('call_func', 'wrap') and skip == 2: return caller_name(4) return ".".join([module_name, function_name]) def same_file(a, b): """ Return 0 if A and B have nothing in common return 1 if A and B are actually the same path return 2 if B is a subfolder of A """ a = os.path.normpath(os.path.abspath(a)) b = os.path.normpath(os.path.abspath(b)) if sabnzbd.WIN32 or sabnzbd.DARWIN: a = a.lower() b = b.lower() if b.startswith(a): return 2 if "samefile" in os.path.__dict__: try: return int(os.path.samefile(a, b)) except: return 0 else: return int(a == b) def exit_sab(value): """ Leave the program after flushing stderr/stdout """ sys.stderr.flush() sys.stdout.flush() if getattr(sys, 'frozen', None) == 'macosx_app': sabnzbd.SABSTOP = True from PyObjCTools import AppHelper AppHelper.stopEventLoop() sys.exit(value) def split_host(srv): """ Split host:port notation, allowing for IPV6 """ # Cannot use split, because IPV6 of "a:b:c:port" notation # Split on the last ':' mark = srv.rfind(':') if mark < 0: host = srv else: host = srv[0: mark] port = srv[mark + 1:] try: port = int(port) except: port = None return (host, port) def get_from_url(url): """ Retrieve URL and return content """ try: return urllib2.urlopen(url).read() except: return None def check_mount(path): """ Return False if volume isn't mounted on Linux or OSX Retry 6 times with an interval of 1 sec. """ if sabnzbd.DARWIN: m = re.search(r'^(/Volumes/[^/]+)/', path, re.I) elif sabnzbd.WIN32: m = re.search(r'^([a-z]:\\)', path, re.I) else: m = re.search(r'^(/(?:mnt|media)/[^/]+)/', path) if m: for n in xrange(cfg.wait_ext_drive() or 1): if os.path.exists(m.group(1)): return True logging.debug('Waiting for %s to come online', m.group(1)) time.sleep(1) return not m def get_cache_limit(): """ Depending on OS, calculate cache limits. In ArticleCache it will make sure we stay within system limits for 32/64 bit """ # Calculate, if possible try: if sabnzbd.WIN32: # Windows mem_bytes = get_windows_memory() elif sabnzbd.DARWIN: # macOS mem_bytes = get_darwin_memory() else: # Linux mem_bytes = (os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')) # Use 1/4th of available memory mem_bytes = mem_bytes/4 # We don't want to set a value that's too high if mem_bytes > from_units(DEF_ARTICLE_CACHE_MAX): return DEF_ARTICLE_CACHE_MAX # We make sure it's at least a valid value if mem_bytes > from_units('32M'): return to_units(mem_bytes) except: pass # Always at least minimum on Windows/macOS if sabnzbd.WIN32 and sabnzbd.DARWIN: return DEF_ARTICLE_CACHE_DEFAULT # If failed, leave empty for Linux so user needs to decide return '' def get_windows_memory(): """ Use ctypes to extract available memory """ class MEMORYSTATUSEX(ctypes.Structure): _fields_ = [ ("dwLength", ctypes.c_ulong), ("dwMemoryLoad", ctypes.c_ulong), ("ullTotalPhys", ctypes.c_ulonglong), ("ullAvailPhys", ctypes.c_ulonglong), ("ullTotalPageFile", ctypes.c_ulonglong), ("ullAvailPageFile", ctypes.c_ulonglong), ("ullTotalVirtual", ctypes.c_ulonglong), ("ullAvailVirtual", ctypes.c_ulonglong), ("sullAvailExtendedVirtual", ctypes.c_ulonglong), ] def __init__(self): # have to initialize this to the size of MEMORYSTATUSEX self.dwLength = ctypes.sizeof(self) super(MEMORYSTATUSEX, self).__init__() stat = MEMORYSTATUSEX() ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat)) return stat.ullTotalPhys def get_darwin_memory(): """ Use system-call to extract total memory on macOS """ system_output = sabnzbd.newsunpack.run_simple(['sysctl', 'hw.memsize']) return float(system_output.split()[1]) ############################################################################## # Locked directory operations to avoid problems with simultaneous add/remove ############################################################################## DIR_LOCK = threading.RLock() @synchronized(DIR_LOCK) def get_unique_path(dirpath, n=0, create_dir=True): """ Determine a unique folder or filename """ if not check_mount(dirpath): return dirpath path = dirpath if n: path = "%s.%s" % (dirpath, n) if not os.path.exists(path): if create_dir: return create_dirs(path) else: return path else: return get_unique_path(dirpath, n=n + 1, create_dir=create_dir) @synchronized(DIR_LOCK) def get_unique_filename(path): """ Check if path is unique. If not, add number like: "/path/name.NUM.ext". """ num = 1 new_path, fname = os.path.split(path) name, ext = os.path.splitext(fname) while os.path.exists(path): fname = "%s.%d%s" % (name, num, ext) num += 1 path = os.path.join(new_path, fname) return path @synchronized(DIR_LOCK) def create_dirs(dirpath): """ Create directory tree, obeying permissions """ if not os.path.exists(dirpath): logging.info('Creating directories: %s', dirpath) if not create_all_dirs(dirpath, True): logging.error(T('Failed making (%s)'), clip_path(dirpath)) return None return dirpath @synchronized(DIR_LOCK) def move_to_path(path, new_path): """ Move a file to a new path, optionally give unique filename Return (ok, new_path) """ ok = True overwrite = cfg.overwrite_files() new_path = os.path.abspath(new_path) if overwrite and os.path.exists(new_path): try: remove_file(new_path) except: overwrite = False if not overwrite: new_path = get_unique_filename(new_path) if new_path: logging.debug("Moving (overwrite: %s) %s => %s", overwrite, path, new_path) try: # First try cheap rename renamer(path, new_path) except: # Cannot rename, try copying logging.debug("File could not be renamed, trying copying: %s", path) try: if not os.path.exists(os.path.dirname(new_path)): create_dirs(os.path.dirname(new_path)) shutil.copyfile(path, new_path) remove_file(path) except: # Check if the old-file actually exists (possible delete-delays) if not os.path.exists(path): logging.debug("File not moved, original path gone: %s", path) return True, None if not (cfg.marker_file() and cfg.marker_file() in path): logging.error(T('Failed moving %s to %s'), clip_path(path), clip_path(new_path)) logging.info("Traceback: ", exc_info=True) ok = False return ok, new_path @synchronized(DIR_LOCK) def cleanup_empty_directories(path): """ Remove all empty folders inside (and including) 'path' """ path = os.path.normpath(path) while 1: repeat = False for root, dirs, files in os.walk(path, topdown=False): if not dirs and not files and root != path: try: remove_dir(root) repeat = True except: pass if not repeat: break try: remove_dir(path) except: pass @synchronized(DIR_LOCK) def get_filepath(path, nzo, filename): """ Create unique filepath """ # This procedure is only used by the Assembler thread # It does no umask setting # It uses the dir_lock for the (rare) case that the # download_dir is equal to the complete_dir. dName = nzo.work_name if not nzo.created: for n in xrange(200): dName = dirname if n: dName += '.' + str(n) try: os.mkdir(os.path.join(path, dName)) break except: pass nzo.work_name = dName nzo.created = True fPath = os.path.join(os.path.join(path, dName), filename) fPath, ext = os.path.splitext(fPath) n = 0 while True: if n: fullPath = "%s.%d%s" % (fPath, n, ext) else: fullPath = fPath + ext if os.path.exists(fullPath): n = n + 1 else: break return fullPath @synchronized(DIR_LOCK) def renamer(old, new): """ Rename file/folder with retries for Win32 """ # Sanitize last part of new name path, name = os.path.split(new) # Use the more stringent folder rename to end up with a nicer name, # but do not trim size new = os.path.join(path, sanitize_foldername(name, False)) logging.debug('Renaming "%s" to "%s"', old, new) if sabnzbd.WIN32: retries = 15 while retries > 0: # First we try 3 times with os.rename if retries > 12: try: os.rename(old, new) return except: retries -= 1 time.sleep(3) continue # Now we try the back-up method logging.debug('Could not rename, trying move for %s to %s', old, new) try: shutil.move(old, new) return except WindowsError, err: logging.debug('Error renaming "%s" to "%s" <%s>', old, new, err) if err[0] == 32: logging.debug('Retry rename %s to %s', old, new) retries -= 1 else: raise WindowsError(err) time.sleep(3) raise WindowsError(err) else: shutil.move(old, new) @synchronized(DIR_LOCK) def remove_dir(path): """ Remove directory with retries for Win32 """ if sabnzbd.WIN32: retries = 15 while retries > 0: try: remove_dir(path) return except WindowsError, err: if err[0] == 32: logging.debug('Retry delete %s', path) retries -= 1 else: raise WindowsError(err) time.sleep(3) raise WindowsError(err) else: remove_dir(path) @synchronized(DIR_LOCK) def remove_all(path, pattern='*', keep_folder=False, recursive=False): """ Remove folder and all its content (optionally recursive) """ if os.path.exists(path): files = globber_full(path, pattern) if pattern == '*' and not sabnzbd.WIN32: files.extend(globber_full(path, '.*')) for f in files: if os.path.isfile(f): try: remove_file(f) except: logging.info('Cannot remove file %s', f) elif recursive: remove_all(f, pattern, False, True) if not keep_folder: try: remove_dir(path) except: logging.info('Cannot remove folder %s', path) def remove_file(path): """ Wrapper function so any file removal is logged """ logging.debug('[%s] Deleting file %s', caller_name(), path) os.remove(path) def remove_dir(dir): """ Wrapper function so any dir removal is logged """ logging.debug('[%s] Deleting dir %s', caller_name(), dir) os.rmdir(dir) def trim_win_path(path): """ Make sure Windows path stays below 70 by trimming last part """ if sabnzbd.WIN32 and len(path) > 69: path, folder = os.path.split(path) maxlen = 69 - len(path) if len(folder) > maxlen: folder = folder[:maxlen] path = os.path.join(path, folder).rstrip('. ') return path def make_script_path(script): """ Return full script path, if any valid script exists, else None """ s_path = None path = cfg.script_dir.get_path() if path and script: if script.lower() not in ('none', 'default'): s_path = os.path.join(path, script) if not os.path.exists(s_path): s_path = None return s_path def get_admin_path(name, future): """ Return news-style full path to job-admin folder of names job or else the old cache path """ if future: return os.path.join(cfg.admin_dir.get_path(), FUTURE_Q_FOLDER) else: return os.path.join(os.path.join(cfg.download_dir.get_path(), name), JOB_ADMIN) def on_cleanup_list(filename, skip_nzb=False): """ Return True if a filename matches the clean-up list """ lst = cfg.cleanup_list() if lst: name, ext = os.path.splitext(filename) ext = ext.strip().lower() name = name.strip() for k in lst: item = k.strip().strip('.').lower() item = '.' + item if (item == ext or (ext == '' and item == name)) and not (skip_nzb and item == '.nzb'): return True return False def get_ext(filename): """ Return lowercased file extension """ try: return os.path.splitext(filename)[1].lower() except: return '' def get_filename(path): """ Return path without the file extension """ try: return os.path.split(path)[1] except: return '' def memory_usage(): try: # Probably only works on Linux because it uses /proc//statm t = open('/proc/%d/statm' % os.getpid()) v = t.read().split() t.close() virt = int(_PAGE_SIZE * int(v[0]) / MEBI) res = int(_PAGE_SIZE * int(v[1]) / MEBI) return "V=%sM R=%sM" % (virt, res) except IOError: pass except: logging.debug('Error retrieving memory usage') logging.info("Traceback: ", exc_info=True) else: return '' try: _PAGE_SIZE = os.sysconf("SC_PAGE_SIZE") except: _PAGE_SIZE = 0 _HAVE_STATM = _PAGE_SIZE and memory_usage() def loadavg(): """ Return 1, 5 and 15 minute load average of host or "" if not supported """ p = '' if not sabnzbd.WIN32 and not sabnzbd.DARWIN: opt = cfg.show_sysload() if opt: try: p = '%.2f | %.2f | %.2f' % os.getloadavg() except: pass if opt > 1 and _HAVE_STATM: p = '%s | %s' % (p, memory_usage()) return p def format_time_string(seconds, days=0): """ Return a formatted and translated time string """ def unit(single, n): if n == 1: return sabnzbd.api.Ttemplate(single) else: return sabnzbd.api.Ttemplate(single + 's') seconds = int_conv(seconds) completestr = [] if days: completestr.append('%s %s' % (days, unit('day', days))) if (seconds / 3600) >= 1: completestr.append('%s %s' % (seconds / 3600, unit('hour', (seconds / 3600)))) seconds -= (seconds / 3600) * 3600 if (seconds / 60) >= 1: completestr.append('%s %s' % (seconds / 60, unit('minute', (seconds / 60)))) seconds -= (seconds / 60) * 60 if seconds > 0: completestr.append('%s %s' % (seconds, unit('second', seconds))) elif not completestr: completestr.append('0 %s' % unit('second', 0)) return ' '.join(completestr) def int_conv(value): """ Safe conversion to int (can handle None) """ try: value = int(value) except: value = 0 return value ############################################################################## # Diskfree ############################################################################## def find_dir(p): """ Return first folder level that exists in this path """ x = 'x' while x and not os.path.exists(p): p, x = os.path.split(p) return p if sabnzbd.WIN32: # windows diskfree try: # Careful here, because win32api test hasn't been done yet! import win32api except: pass def diskspace_base(_dir): """ Return amount of free and used diskspace in GBytes """ _dir = find_dir(_dir) try: available, disk_size, total_free = win32api.GetDiskFreeSpaceEx(_dir) return disk_size / GIGI, available / GIGI except: return 0.0, 0.0 else: try: os.statvfs # posix diskfree def diskspace_base(_dir): """ Return amount of free and used diskspace in GBytes """ _dir = find_dir(_dir) try: s = os.statvfs(_dir) if s.f_blocks < 0: disk_size = float(sys.maxint) * float(s.f_frsize) else: disk_size = float(s.f_blocks) * float(s.f_frsize) if s.f_bavail < 0: available = float(sys.maxint) * float(s.f_frsize) else: available = float(s.f_bavail) * float(s.f_frsize) return disk_size / GIGI, available / GIGI except: return 0.0, 0.0 except ImportError: def diskspace_base(_dir): return 20.0, 10.0 # Store all results to speed things up __DIRS_CHECKED = [] __DISKS_SAME = None __LAST_DISK_RESULT = {'download_dir': [], 'complete_dir': []} __LAST_DISK_CALL = 0 def diskspace(force=False): """ Wrapper to cache results """ global __DIRS_CHECKED, __DISKS_SAME, __LAST_DISK_RESULT, __LAST_DISK_CALL # Reset everything when folders changed dirs_to_check = [cfg.download_dir.get_path(), cfg.complete_dir.get_path()] if __DIRS_CHECKED != dirs_to_check: __DIRS_CHECKED = dirs_to_check __DISKS_SAME = None __LAST_DISK_RESULT = {'download_dir': [], 'complete_dir': []} __LAST_DISK_CALL = 0 # When forced, ignore any cache to avoid problems in UI if force: __LAST_DISK_CALL = 0 # Check against cache if time.time() > __LAST_DISK_CALL + 10.0: # Same disk? Then copy-paste __LAST_DISK_RESULT['download_dir'] = diskspace_base(cfg.download_dir.get_path()) __LAST_DISK_RESULT['complete_dir'] = __LAST_DISK_RESULT['download_dir'] if __DISKS_SAME else diskspace_base(cfg.complete_dir.get_path()) __LAST_DISK_CALL = time.time() # Do we know if it's same disk? if __DISKS_SAME is None: __DISKS_SAME = (__LAST_DISK_RESULT['download_dir'] == __LAST_DISK_RESULT['complete_dir']) return __LAST_DISK_RESULT ############################################################################## # Other support functions ############################################################################## def create_https_certificates(ssl_cert, ssl_key): """ Create self-signed HTTPS certificates and store in paths 'ssl_cert' and 'ssl_key' """ if not sabnzbd.HAVE_CRYPTOGRAPHY: logging.error(T('%s missing'), 'Python Cryptography') return False # Save the key and certificate to disk try: from sabnzbd.utils.certgen import generate_key, generate_local_cert private_key = generate_key(key_size=2048, output_file=ssl_key) generate_local_cert(private_key, days_valid=3560, output_file=ssl_cert, LN=u'SABnzbd', ON=u'SABnzbd', CN=u'localhost') logging.info('Self-signed certificates generated successfully') except: logging.error(T('Error creating SSL key and certificate')) logging.info("Traceback: ", exc_info=True) return False return True def get_all_passwords(nzo): """ Get all passwords, from the NZB, meta and password file """ if nzo.password: logging.info('Found a password that was set by the user: %s', nzo.password) passwords = [nzo.password.strip()] else: passwords = [] meta_passwords = nzo.meta.get('password', []) pw = nzo.nzo_info.get('password') if pw: meta_passwords.append(pw) if meta_passwords: if nzo.password == meta_passwords[0]: # this nzo.password came from meta, so don't use it twice passwords.extend(meta_passwords[1:]) else: passwords.extend(meta_passwords) logging.info('Read %s passwords from meta data in NZB: %s', len(meta_passwords), meta_passwords) pw_file = cfg.password_file.get_path() if pw_file: try: with open(pw_file, 'r') as pwf: lines = pwf.read().split('\n') # Remove empty lines and space-only passwords and remove surrounding spaces pws = [pw.strip('\r\n ') for pw in lines if pw.strip('\r\n ')] logging.debug('Read these passwords from file: %s', pws) passwords.extend(pws) logging.info('Read %s passwords from file %s', len(pws), pw_file) # Check size if len(pws) > 30: logging.warning(T('Your password file contains more than 30 passwords, testing all these passwords takes a lot of time. Try to only list useful passwords.')) except: logging.warning('Failed to read the passwords file %s', pw_file) if nzo.password: # If an explicit password was set, add a retry without password, just in case. passwords.append('') elif not passwords or nzo.encrypted < 1: # If we're not sure about encryption, start with empty password # and make sure we have at least the empty password passwords.insert(0, '') return passwords def find_on_path(targets): """ Search the PATH for a program and return full path """ if sabnzbd.WIN32: paths = os.getenv('PATH').split(';') else: paths = os.getenv('PATH').split(':') if isinstance(targets, basestring): targets = (targets, ) for path in paths: for target in targets: target_path = os.path.abspath(os.path.join(path, target)) if os.path.isfile(target_path) and os.access(target_path, os.X_OK): return target_path return None def ip_extract(): """ Return list of IP addresses of this system """ ips = [] program = find_on_path('ip') if program: program = [program, 'a'] else: program = find_on_path('ifconfig') if program: program = [program] if sabnzbd.WIN32 or not program: try: info = socket.getaddrinfo(socket.gethostname(), None) except: # Hostname does not resolve, use localhost info = socket.getaddrinfo('localhost', None) for item in info: ips.append(item[4][0]) else: p = subprocess.Popen(program, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=None, creationflags=0) output = p.stdout.read() p.wait() for line in output.split('\n'): m = RE_IP4.search(line) if not (m and m.group(2)): m = RE_IP6.search(line) if m and m.group(2): ips.append(m.group(2)) return ips def is_writable(path): """ Return True is file is writable (also when non-existent) """ if os.path.isfile(path): return bool(os.stat(path).st_mode & stat.S_IWUSR) else: return True def get_base_url(url): """ Return only the true root domain for the favicon, so api.oznzb.com -> oznzb.com But also api.althub.co.za -> althub.co.za """ url_host = urlparse(url).hostname if url_host: url_split = url_host.split(".") # Exception for localhost and IPv6 addresses if len(url_split) < 3: return url_host return ".".join(len(url_split[-2]) < 4 and url_split[-3:] or url_split[-2:]) else: return '' def match_str(text, matches): """ Return first matching element of list 'matches' in 'text', otherwise None """ for match in matches: if match in text: return match return None def starts_with_path(path, prefix): """ Return True if 'path' starts with 'prefix', considering case-sensitivity of the file system """ if sabnzbd.WIN32: return clip_path(path).lower().startswith(prefix.lower()) elif sabnzbd.DARWIN: return path.lower().startswith(prefix.lower()) else: return path.startswith(prefix) def set_chmod(path, permissions, report): """ Set 'permissions' on 'path', report any errors when 'report' is True """ try: logging.debug('Applying permissions %s (octal) to %s', oct(permissions), path) os.chmod(path, permissions) except: lpath = path.lower() if report and '.appledouble' not in lpath and '.ds_store' not in lpath: logging.error(T('Cannot change permissions of %s'), clip_path(path)) logging.info("Traceback: ", exc_info=True) def set_permissions(path, recursive=True): """ Give folder tree and its files their proper permissions """ if not sabnzbd.WIN32: umask = cfg.umask() try: # Make sure that user R+W+X is on umask = int(umask, 8) | int('0700', 8) report = True except ValueError: # No or no valid permissions # Use the effective permissions of the session # Don't report errors (because the system might not support it) umask = int('0777', 8) & (sabnzbd.ORG_UMASK ^ int('0777', 8)) report = False # Remove X bits for files umask_file = umask & int('7666', 8) if os.path.isdir(path): if recursive: # Parse the dir/file tree and set permissions for root, _dirs, files in os.walk(path): set_chmod(root, umask, report) for name in files: set_chmod(os.path.join(root, name), umask_file, report) else: set_chmod(path, umask, report) else: set_chmod(path, umask_file, report) def clip_path(path): r""" Remove \\?\ or \\?\UNC\ prefix from Windows path """ if sabnzbd.WIN32 and path and '?' in path: path = path.replace(u'\\\\?\\UNC\\', u'\\\\', 1).replace(u'\\\\?\\', u'', 1) return path def long_path(path): """ For Windows, convert to long style path; others, return same path """ if sabnzbd.WIN32 and path and not path.startswith(u'\\\\?\\'): if path.startswith('\\\\'): # Special form for UNC paths path = path.replace(u'\\\\', u'\\\\?\\UNC\\', 1) else: # Normal form for local paths path = u'\\\\?\\' + path return path def fix_unix_encoding(folder): """ Fix bad name encoding for Unix systems """ if not sabnzbd.WIN32 and not sabnzbd.DARWIN and gUTF: for root, dirs, files in os.walk(folder.encode('utf-8')): for name in files: new_name = special_fixer(name).encode('utf-8') if name != new_name: try: shutil.move(os.path.join(root, name), os.path.join(root, new_name)) except: logging.info('Cannot correct name of %s', os.path.join(root, name)) def get_urlbase(url): """ Return the base URL (like http://server.domain.com/) """ parsed_uri = urlparse(url) return '{uri.scheme}://{uri.netloc}/'.format(uri=parsed_uri) def nntp_to_msg(text): """ Format raw NNTP data for display """ if isinstance(text, list): text = text[0] lines = text.split('\r\n') return lines[0] SABnzbd-2.3.2/sabnzbd/newsunpack.py0000644000000000000000000026652113217005257015320 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.newsunpack """ import os import sys import re import subprocess import logging import time import binascii import shutil import sabnzbd from sabnzbd.encoding import TRANS, unicoder, platform_encode, deunicode import sabnzbd.utils.rarfile as rarfile from sabnzbd.misc import format_time_string, find_on_path, make_script_path, int_conv, \ real_path, globber, globber_full, get_all_passwords, renamer, clip_path, \ has_win_device, calc_age, long_path, remove_file from sabnzbd.sorting import SeriesSorter import sabnzbd.cfg as cfg from sabnzbd.constants import Status if sabnzbd.WIN32: try: import win32api from win32con import SW_HIDE from win32process import STARTF_USESHOWWINDOW, IDLE_PRIORITY_CLASS # Use patched version of subprocess module for Unicode on Windows import subprocessww except ImportError: pass else: # Define dummy WindowsError for non-Windows class WindowsError(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) # Load the regular POpen (which is now patched on Windows) from subprocess import Popen # Regex globals RAR_RE = re.compile(r'\.(?Ppart\d*\.rar|rar|r\d\d|s\d\d|t\d\d|u\d\d|v\d\d|\d\d\d)$', re.I) RAR_RE_V3 = re.compile(r'\.(?Ppart\d*)$', re.I) LOADING_RE = re.compile(r'^Loading "(.+)"') TARGET_RE = re.compile(r'^(?:File|Target): "(.+)" -') EXTRACTFROM_RE = re.compile(r'^Extracting\sfrom\s(.+)') EXTRACTED_RE = re.compile(r'^(Extracting|Creating|...)\s+(.*?)\s+OK\s*$') SPLITFILE_RE = re.compile(r'\.(\d\d\d$)', re.I) ZIP_RE = re.compile(r'\.(zip$)', re.I) SEVENZIP_RE = re.compile(r'\.7z$', re.I) SEVENMULTI_RE = re.compile(r'\.7z\.\d+$', re.I) TS_RE = re.compile(r'\.(\d+)\.(ts$)', re.I) PAR2_COMMAND = None MULTIPAR_COMMAND = None RAR_COMMAND = None NICE_COMMAND = None ZIP_COMMAND = None SEVEN_COMMAND = None IONICE_COMMAND = None RAR_PROBLEM = False PAR2_MT = True RAR_VERSION = 0 def find_programs(curdir): """ Find external programs """ def check(path, program): p = os.path.abspath(os.path.join(path, program)) if os.access(p, os.X_OK): return p else: return None if sabnzbd.DARWIN: sabnzbd.newsunpack.PAR2_COMMAND = check(curdir, 'osx/par2/par2-sl64') sabnzbd.newsunpack.RAR_COMMAND = check(curdir, 'osx/unrar/unrar') sabnzbd.newsunpack.SEVEN_COMMAND = check(curdir, 'osx/7zip/7za') if sabnzbd.WIN32: if sabnzbd.WIN64: # 64 bit versions sabnzbd.newsunpack.MULTIPAR_COMMAND = check(curdir, 'win/par2/multipar/par2j64.exe') sabnzbd.newsunpack.RAR_COMMAND = check(curdir, 'win/unrar/x64/UnRAR.exe') else: # 32 bit versions sabnzbd.newsunpack.MULTIPAR_COMMAND = check(curdir, 'win/par2/multipar/par2j.exe') sabnzbd.newsunpack.RAR_COMMAND = check(curdir, 'win/unrar/UnRAR.exe') sabnzbd.newsunpack.PAR2_COMMAND = check(curdir, 'win/par2/par2.exe') sabnzbd.newsunpack.SEVEN_COMMAND = check(curdir, 'win/7zip/7za.exe') else: if not sabnzbd.newsunpack.PAR2_COMMAND: sabnzbd.newsunpack.PAR2_COMMAND = find_on_path('par2') if not sabnzbd.newsunpack.RAR_COMMAND: sabnzbd.newsunpack.RAR_COMMAND = find_on_path(('unrar', 'rar', 'unrar3', 'rar3',)) sabnzbd.newsunpack.NICE_COMMAND = find_on_path('nice') sabnzbd.newsunpack.IONICE_COMMAND = find_on_path('ionice') if not sabnzbd.newsunpack.ZIP_COMMAND: sabnzbd.newsunpack.ZIP_COMMAND = find_on_path('unzip') if not sabnzbd.newsunpack.SEVEN_COMMAND: sabnzbd.newsunpack.SEVEN_COMMAND = find_on_path('7za') if not sabnzbd.newsunpack.SEVEN_COMMAND: sabnzbd.newsunpack.SEVEN_COMMAND = find_on_path('7z') if not (sabnzbd.WIN32 or sabnzbd.DARWIN): # Run check on rar version version, original = unrar_check(sabnzbd.newsunpack.RAR_COMMAND) sabnzbd.newsunpack.RAR_PROBLEM = not original or version < sabnzbd.constants.REC_RAR_VERSION sabnzbd.newsunpack.RAR_VERSION = version # Run check on par2-multicore sabnzbd.newsunpack.PAR2_MT = par2_mt_check(sabnzbd.newsunpack.PAR2_COMMAND) ENV_NZO_FIELDS = ['bytes', 'bytes_downloaded', 'bytes_tried', 'cat', 'duplicate', 'encrypted', 'fail_msg', 'filename', 'final_name', 'group', 'nzo_id', 'oversized', 'password', 'pp', 'priority', 'repair', 'script', 'status', 'unpack', 'unwanted_ext', 'url'] def external_processing(extern_proc, nzo, complete_dir, nicename, status): """ Run a user postproc script, return console output and exit value """ failure_url = nzo.nzo_info.get('failure', '') command = [str(extern_proc), str(complete_dir), str(nzo.filename), str(nicename), '', str(nzo.cat), str(nzo.group), str(status), str(failure_url)] # Add path to original NZB nzb_paths = globber_full(nzo.workpath, '*.gz') # Fields not in the NZO directly extra_env_fields = {'failure_url': failure_url, 'complete_dir': complete_dir, 'pp_status': status, 'download_time': nzo.nzo_info.get('download_time', ''), 'avg_bps': int(nzo.avg_bps_total / nzo.avg_bps_freq) if nzo.avg_bps_freq else 0, 'age': calc_age(nzo.avg_date), 'orig_nzb_gz': clip_path(nzb_paths[0]) if nzb_paths else '', 'program_dir': sabnzbd.DIR_PROG, 'par2_command': sabnzbd.newsunpack.PAR2_COMMAND, 'multipar_command': sabnzbd.newsunpack.MULTIPAR_COMMAND, 'rar_command': sabnzbd.newsunpack.RAR_COMMAND, 'zip_command': sabnzbd.newsunpack.ZIP_COMMAND, '7zip_command': sabnzbd.newsunpack.SEVEN_COMMAND, 'version': sabnzbd.__version__} try: stup, need_shell, command, creationflags = build_command(command) env = create_env(nzo, extra_env_fields) logging.info('Running external script %s(%s, %s, %s, %s, %s, %s, %s, %s)', extern_proc, complete_dir, nzo.filename, nicename, '', nzo.cat, nzo.group, status, failure_url) p = Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, env=env, creationflags=creationflags) # Follow the output, so we can abort it proc = p.stdout if p.stdin: p.stdin.close() line = '' lines = [] while 1: line = proc.readline() if not line: break line = line.strip() lines.append(line) # Show current line in history nzo.set_action_line(T('Running script'), unicoder(line)) # Check if we should still continue if not nzo.pp_active: p.kill() lines.append(T('PostProcessing was aborted (%s)') % T('Script')) # Print at least what we got output = '\n'.join(lines) return output, 1 except: logging.debug("Failed script %s, Traceback: ", extern_proc, exc_info=True) return "Cannot run script %s\r\n" % extern_proc, -1 output = '\n'.join(lines) ret = p.wait() return output, ret def external_script(script, p1, p2, p3=None, p4=None): """ Run a user script with two parameters, return console output and exit value """ command = [script, p1, p2, p3, p4] try: stup, need_shell, command, creationflags = build_command(command) env = create_env() logging.info('Running user script %s(%s, %s)', script, p1, p2) p = Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, env=env, creationflags=creationflags) except: logging.debug("Failed script %s, Traceback: ", script, exc_info=True) return "Cannot run script %s\r\n" % script, -1 output = p.stdout.read() ret = p.wait() return output, ret def unpack_magic(nzo, workdir, workdir_complete, dele, one_folder, joinables, zips, rars, sevens, ts, depth=0): """ Do a recursive unpack from all archives in 'workdir' to 'workdir_complete' """ if depth > 5: logging.warning(T('Unpack nesting too deep [%s]'), nzo.final_name) return False, [] depth += 1 if depth == 1: # First time, ignore anything in workdir_complete xjoinables, xzips, xrars, xsevens, xts = build_filelists(workdir) else: xjoinables, xzips, xrars, xsevens, xts = build_filelists(workdir, workdir_complete, check_both=dele) rerun = False force_rerun = False newfiles = [] error = 0 new_joins = new_rars = new_zips = new_ts = None if cfg.enable_filejoin(): new_joins = [jn for jn in xjoinables if jn not in joinables] if new_joins: logging.info('Filejoin starting on %s', workdir) error, newf = file_join(nzo, workdir, workdir_complete, dele, new_joins) if newf: newfiles.extend(newf) logging.info('Filejoin finished on %s', workdir) nzo.set_action_line() rerun = not error if cfg.enable_unrar(): new_rars = [rar for rar in xrars if rar not in rars] if new_rars: logging.info('Unrar starting on %s', workdir) error, newf = rar_unpack(nzo, workdir, workdir_complete, dele, one_folder, new_rars) if newf: newfiles.extend(newf) logging.info('Unrar finished on %s', workdir) nzo.set_action_line() rerun = not error if cfg.enable_7zip(): new_sevens = [seven for seven in xsevens if seven not in sevens] if new_sevens: logging.info('7za starting on %s', workdir) if unseven(nzo, workdir, workdir_complete, dele, one_folder, new_sevens): error = True logging.info('7za finished on %s', workdir) nzo.set_action_line() rerun = not error if cfg.enable_unzip(): new_zips = [zip for zip in xzips if zip not in zips] if new_zips: logging.info('Unzip starting on %s', workdir) if SEVEN_COMMAND: if unseven(nzo, workdir, workdir_complete, dele, one_folder, new_zips): error = True else: if unzip(nzo, workdir, workdir_complete, dele, one_folder, new_zips): error = True logging.info('Unzip finished on %s', workdir) nzo.set_action_line() rerun = not error if cfg.enable_tsjoin(): new_ts = [_ts for _ts in xts if _ts not in ts] if new_ts: logging.info('TS Joining starting on %s', workdir) error, newf = file_join(nzo, workdir, workdir_complete, dele, new_ts) if newf: newfiles.extend(newf) logging.info('TS Joining finished on %s', workdir) nzo.set_action_line() rerun = not error # During a Retry we might miss files that failed during recursive unpack if nzo.reuse and depth == 1 and any(build_filelists(workdir, workdir_complete)): rerun = True # Double-check that we didn't miss any files in workdir # But only if dele=True, otherwise of course there will be files left if rerun and dele and depth == 1 and any(build_filelists(workdir)): force_rerun = True # Clear lists to force re-scan of files xjoinables, xzips, xrars, xsevens, xts = ([], [], [], [], []) if rerun and (cfg.enable_recursive() or new_ts or new_joins or force_rerun): z, y = unpack_magic(nzo, workdir, workdir_complete, dele, one_folder, xjoinables, xzips, xrars, xsevens, xts, depth) if z: error = z if y: newfiles.extend(y) return error, newfiles ############################################################################## # Filejoin Functions ############################################################################## def match_ts(file): """ Return True if file is a joinable TS file """ match = TS_RE.search(file) if not match: return False, '', 0 num = int(match.group(1)) try: set = file[:match.start()] set += '.ts' except: set = '' return match, set, num def clean_up_joinables(names): """ Remove joinable files and their .1 backups """ for name in names: if os.path.exists(name): try: remove_file(name) except: pass name1 = name + ".1" if os.path.exists(name1): try: remove_file(name1) except: pass def get_seq_number(name): """ Return sequence number if name as an int """ head, tail = os.path.splitext(name) if tail == '.ts': match, set, num = match_ts(name) else: num = tail[1:] if num.isdigit(): return int(num) else: return 0 def file_join(nzo, workdir, workdir_complete, delete, joinables): """ Join and joinable files in 'workdir' to 'workdir_complete' and when successful, delete originals """ newfiles = [] bufsize = 24 * 1024 * 1024 # Create matching sets from the list of files joinable_sets = {} joinable_set = None for joinable in joinables: head, tail = os.path.splitext(joinable) if tail == '.ts': head = match_ts(joinable)[1] if head not in joinable_sets: joinable_sets[head] = [] joinable_sets[head].append(joinable) logging.debug("joinable_sets: %s", joinable_sets) try: # Handle each set for joinable_set in joinable_sets: current = joinable_sets[joinable_set] joinable_sets[joinable_set].sort() # If par2 already did the work, just remove the files if os.path.exists(joinable_set): logging.debug("file_join(): Skipping %s, (probably) joined by par2", joinable_set) if delete: clean_up_joinables(current) # done, go to next set continue # Only join when there is more than one file size = len(current) if size < 2: continue # Prepare joined file filename = joinable_set if workdir_complete: filename = filename.replace(workdir, workdir_complete) logging.debug("file_join(): Assembling %s", filename) joined_file = open(filename, 'ab') # Join the segments n = get_seq_number(current[0]) seq_error = n > 1 for joinable in current: if get_seq_number(joinable) != n: seq_error = True perc = (100.0 / size) * n logging.debug("Processing %s", joinable) nzo.set_action_line(T('Joining'), '%.0f%%' % perc) f = open(joinable, 'rb') shutil.copyfileobj(f, joined_file, bufsize) f.close() if delete: remove_file(joinable) n += 1 # Remove any remaining .1 files clean_up_joinables(current) # Finish up joined_file.flush() joined_file.close() newfiles.append(filename) if seq_error: msg = T('Incomplete sequence of joinable files') nzo.fail_msg = T('File join of %s failed') % unicoder(joinable_set) nzo.set_unpack_info('Filejoin', T('[%s] Error "%s" while joining files') % (unicoder(joinable_set), msg)) logging.error(T('Error "%s" while running file_join on %s'), msg, nzo.final_name) else: msg = T('[%s] Joined %s files') % (unicoder(joinable_set), size) nzo.set_unpack_info('Filejoin', msg) except: msg = sys.exc_info()[1] nzo.fail_msg = T('File join of %s failed') % msg nzo.set_unpack_info('Filejoin', T('[%s] Error "%s" while joining files') % (unicoder(joinable_set), msg)) logging.error(T('Error "%s" while running file_join on %s'), msg, nzo.final_name) return True, [] return False, newfiles ############################################################################## # (Un)Rar Functions ############################################################################## def rar_unpack(nzo, workdir, workdir_complete, delete, one_folder, rars): """ Unpack multiple sets 'rars' of RAR files from 'workdir' to 'workdir_complete. When 'delete' is set, originals will be deleted. When 'one_folder' is set, all files will be in a single folder """ extracted_files = [] success = False rar_sets = {} for rar in rars: rar_set = os.path.splitext(os.path.basename(rar))[0] if RAR_RE_V3.search(rar_set): rar_set = os.path.splitext(rar_set)[0] if rar_set not in rar_sets: rar_sets[rar_set] = [] rar_sets[rar_set].append(rar) logging.debug('Rar_sets: %s', rar_sets) for rar_set in rar_sets: # Run the RAR extractor rar_sets[rar_set].sort(rar_sort) rarpath = rar_sets[rar_set][0] if workdir_complete and rarpath.startswith(workdir): extraction_path = workdir_complete else: extraction_path = os.path.split(rarpath)[0] # Is the direct-unpacker still running? We wait for it if nzo.direct_unpacker: wait_count = 0 last_stats = nzo.direct_unpacker.get_formatted_stats() while nzo.direct_unpacker.is_alive(): logging.debug('DirectUnpacker still alive for %s: %s', nzo.work_name, last_stats) # Bump the file-lock in case it's stuck with nzo.direct_unpacker.next_file_lock: nzo.direct_unpacker.next_file_lock.notify() time.sleep(2) # Did something change? Might be stuck if last_stats == nzo.direct_unpacker.get_formatted_stats(): wait_count += 1 if wait_count > 60: # We abort after 2 minutes of no changes nzo.direct_unpacker.abort() last_stats = nzo.direct_unpacker.get_formatted_stats() # Did we already direct-unpack it? Not when recursive-unpacking if nzo.direct_unpacker and rar_set in nzo.direct_unpacker.success_sets: logging.info("Set %s completed by DirectUnpack", rar_set) fail = False success = True rars, newfiles = nzo.direct_unpacker.success_sets.pop(rar_set) else: logging.info("Extracting rarfile %s (belonging to %s) to %s", rarpath, rar_set, extraction_path) try: fail, newfiles, rars = rar_extract(rarpath, len(rar_sets[rar_set]), one_folder, nzo, rar_set, extraction_path) # Was it aborted? if not nzo.pp_active: fail = True break success = not fail except: success = False fail = True msg = sys.exc_info()[1] nzo.fail_msg = T('Unpacking failed, %s') % msg setname = nzo.final_name nzo.set_unpack_info('Unpack', T('[%s] Error "%s" while unpacking RAR files') % (unicoder(setname), msg)) logging.error(T('Error "%s" while running rar_unpack on %s'), msg, setname) logging.debug("Traceback: ", exc_info=True) if success: logging.debug('rar_unpack(): Rars: %s', rars) logging.debug('rar_unpack(): Newfiles: %s', newfiles) extracted_files.extend(newfiles) # Do not fail if this was a recursive unpack if fail and rarpath.startswith(workdir_complete): # Do not delete the files, leave it to user! logging.info('Ignoring failure to do recursive unpack of %s', rarpath) fail = 0 success = True newfiles = [] # Do not fail if this was maybe just some duplicate fileset # Multipar and par2tbb will detect and log them, par2cmdline will not if fail and rar_set.endswith(('.1', '.2')): # Just in case, we leave the raw files logging.info('Ignoring failure of unpack for possible duplicate file %s', rarpath) fail = 0 success = True newfiles = [] # Delete the old files if we have to if success and delete and newfiles: for rar in rars: try: remove_file(rar) except OSError: if os.path.exists(rar): logging.warning(T('Deleting %s failed!'), rar) brokenrar = '%s.1' % rar if os.path.exists(brokenrar): logging.info("Deleting %s", brokenrar) try: remove_file(brokenrar) except OSError: if os.path.exists(brokenrar): logging.warning(T('Deleting %s failed!'), brokenrar) return fail, extracted_files def rar_extract(rarfile_path, numrars, one_folder, nzo, setname, extraction_path): """ Unpack single rar set 'rarfile' to 'extraction_path', with password tries Return fail==0(ok)/fail==1(error)/fail==2(wrong password), new_files, rars """ fail = 0 new_files = None rars = [] passwords = get_all_passwords(nzo) for password in passwords: if password: logging.debug('Trying unrar with password "%s"', password) msg = T('Trying unrar with password "%s"') % unicoder(password) nzo.fail_msg = msg nzo.set_unpack_info('Unpack', msg) fail, new_files, rars = rar_extract_core(rarfile_path, numrars, one_folder, nzo, setname, extraction_path, password) if fail != 2: break if fail == 2: logging.error('%s (%s)', T('Unpacking failed, archive requires a password'), os.path.split(rarfile_path)[1]) return fail, new_files, rars def rar_extract_core(rarfile_path, numrars, one_folder, nzo, setname, extraction_path, password): """ Unpack single rar set 'rarfile_path' to 'extraction_path' Return fail==0(ok)/fail==1(error)/fail==2(wrong password)/fail==3(crc-error), new_files, rars """ start = time.time() logging.debug("rar_extract(): Extractionpath: %s", extraction_path) if password: password_command = '-p%s' % password else: password_command = '-p-' ############################################################################ if one_folder or cfg.flat_unpack(): action = 'e' else: action = 'x' if cfg.overwrite_files(): overwrite = '-o+' # Enable overwrite rename = '-o+' # Dummy else: overwrite = '-o-' # Disable overwrite rename = '-or' # Auto renaming if sabnzbd.WIN32: # For Unrar to support long-path, we need to cricumvent Python's list2cmdline # See: https://github.com/sabnzbd/sabnzbd/issues/1043 command = ['%s' % RAR_COMMAND, action, '-idp', overwrite, rename, '-ai', password_command, '%s' % clip_path(rarfile_path), '%s\\' % long_path(extraction_path)] elif RAR_PROBLEM: # Use only oldest options (specifically no "-or") command = ['%s' % RAR_COMMAND, action, '-idp', overwrite, password_command, '%s' % rarfile_path, '%s/' % extraction_path] else: # Don't use "-ai" (not needed for non-Windows) command = ['%s' % RAR_COMMAND, action, '-idp', overwrite, rename, password_command, '%s' % rarfile_path, '%s/' % extraction_path] if cfg.ignore_unrar_dates(): command.insert(3, '-tsm-') stup, need_shell, command, creationflags = build_command(command, flatten_command=True) # Get list of all the volumes part of this set logging.debug("Analyzing rar file ... %s found", rarfile.is_rarfile(rarfile_path)) logging.debug("Running unrar %s", command) p = Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, creationflags=creationflags) proc = p.stdout if p.stdin: p.stdin.close() nzo.set_action_line(T('Unpacking'), '00/%02d' % numrars) # Loop over the output from rar! curr = 0 extracted = [] rarfiles = [] fail = 0 inrecovery = False lines = [] while 1: line = proc.readline() if not line: break # Check if we should still continue if not nzo.pp_active: p.kill() msg = T('PostProcessing was aborted (%s)') % T('Unpack') nzo.fail_msg = msg nzo.set_unpack_info('Unpack', msg) nzo.status = Status.FAILED return fail, (), () line = line.strip() lines.append(line) if line.startswith('Extracting from'): filename = TRANS((re.search(EXTRACTFROM_RE, line).group(1))) if filename not in rarfiles: rarfiles.append(filename) curr += 1 nzo.set_action_line(T('Unpacking'), '%02d/%02d' % (curr, numrars)) elif line.find('recovery volumes found') > -1: inrecovery = True # and thus start ignoring "Cannot find volume" for a while logging.debug("unrar recovery start: %s" % line) elif line.startswith('Reconstruct'): # end of reconstruction: 'Reconstructing... 100%' or 'Reconstructing... ' (both success), or 'Reconstruction impossible' inrecovery = False logging.debug("unrar recovery result: %s" % line) elif line.startswith('Cannot find volume') and not inrecovery: filename = os.path.basename(TRANS(line[19:])) nzo.fail_msg = T('Unpacking failed, unable to find %s') % unicoder(filename) msg = (u'[%s] ' + T('Unpacking failed, unable to find %s')) % (setname, filename) nzo.set_unpack_info('Unpack', unicoder(msg)) logging.warning(T('ERROR: unable to find "%s"'), filename) fail = 1 elif line.endswith('- CRC failed'): filename = TRANS(line[:-12].strip()) nzo.fail_msg = T('Unpacking failed, CRC error') msg = (u'[%s] ' + T('ERROR: CRC failed in "%s"')) % (setname, filename) nzo.set_unpack_info('Unpack', unicoder(msg)) logging.warning(T('ERROR: CRC failed in "%s"'), setname) fail = 2 # Older unrar versions report a wrong password as a CRC error elif line.startswith('File too large'): nzo.fail_msg = T('Unpacking failed, file too large for filesystem (FAT?)') msg = (u'[%s] ' + T('Unpacking failed, file too large for filesystem (FAT?)')) % setname nzo.set_unpack_info('Unpack', unicoder(msg)) # ERROR: File too large for file system (bigfile-5000MB) logging.error(T('ERROR: File too large for filesystem (%s)'), setname) fail = 1 elif line.startswith('Write error'): nzo.fail_msg = T('Unpacking failed, write error or disk is full?') msg = (u'[%s] ' + T('Unpacking failed, write error or disk is full?')) % setname nzo.set_unpack_info('Unpack', unicoder(msg)) logging.error(T('ERROR: write error (%s)'), line[11:]) fail = 1 elif line.startswith('Cannot create'): line2 = proc.readline() if 'must not exceed 260' in line2: nzo.fail_msg = T('Unpacking failed, path is too long') msg = u'[%s] %s: %s' % (T('Unpacking failed, path is too long'), setname, unicoder(line[13:])) logging.error(T('ERROR: path too long (%s)'), unicoder(line[13:])) else: nzo.fail_msg = T('Unpacking failed, write error or disk is full?') msg = u'[%s] %s: %s' % (T('Unpacking failed, write error or disk is full?'), setname, unicoder(line[13:])) logging.error(T('ERROR: write error (%s)'), unicoder(line[13:])) nzo.set_unpack_info('Unpack', unicoder(msg)) fail = 1 # Kill the process (can stay in endless loop on Windows Server) p.kill() elif line.startswith('ERROR: '): nzo.fail_msg = T('Unpacking failed, see log') logging.warning(T('ERROR: %s'), (unicoder(line[7:]))) msg = (u'[%s] ' + T('ERROR: %s')) % (setname, line[7:]) nzo.set_unpack_info('Unpack', unicoder(msg)) fail = 1 elif 'The specified password is incorrect' in line or \ ('ncrypted file' in line and (('CRC failed' in line) or ('Checksum error' in line))): # unrar 3.x: "Encrypted file: CRC failed in oLKQfrcNVivzdzSG22a2xo7t001.part1.rar (password incorrect ?)" # unrar 4.x: "CRC failed in the encrypted file oLKQfrcNVivzdzSG22a2xo7t001.part1.rar. Corrupt file or wrong password." # unrar 5.x: "Checksum error in the encrypted file oLKQfrcNVivzdzSG22a2xo7t001.part1.rar. Corrupt file or wrong password." # unrar 5.01 : "The specified password is incorrect." m = re.search(r'encrypted file (.+)\. Corrupt file', line) if not m: # unrar 3.x syntax m = re.search(r'Encrypted file: CRC failed in (.+) \(password', line) if m: filename = TRANS(m.group(1)).strip() else: filename = os.path.split(rarfile_path)[1] nzo.fail_msg = T('Unpacking failed, archive requires a password') msg = (u'[%s][%s] ' + T('Unpacking failed, archive requires a password')) % (setname, filename) nzo.set_unpack_info('Unpack', unicoder(msg)) fail = 2 elif 'is not RAR archive' in line: # Unrecognizable RAR file m = re.search('(.+) is not RAR archive', line) if m: filename = TRANS(m.group(1)).strip() else: filename = '???' nzo.fail_msg = T('Unusable RAR file') msg = ('[%s][%s] ' + T('Unusable RAR file')) % (setname, filename) nzo.set_unpack_info('Unpack', unicoder(msg)) fail = 3 elif 'checksum error' in line: # Corrupt archive # packed data checksum error in volume FILE m = re.search(r'error in volume (.+)', line) if m: filename = TRANS(m.group(1)).strip() else: filename = '???' nzo.fail_msg = T('Corrupt RAR file') msg = ('[%s][%s] ' + T('Corrupt RAR file')) % (setname, filename) nzo.set_unpack_info('Unpack', unicoder(msg)) fail = 3 else: m = re.search(EXTRACTED_RE, line) if m: # In case of flat-unpack, UnRar still prints the whole path (?!) unpacked_file = TRANS(m.group(2)) if cfg.flat_unpack(): unpacked_file = os.path.basename(unpacked_file) extracted.append(real_path(extraction_path, unpacked_file)) if fail: if proc: proc.close() p.wait() logging.debug('UNRAR output %s', '\n'.join(lines)) return fail, (), () if proc: proc.close() p.wait() # Which files did we use to extract this? rarfiles = rar_volumelist(rarfile_path, password, rarfiles) logging.debug('UNRAR output %s', '\n'.join(lines)) nzo.fail_msg = '' msg = T('Unpacked %s files/folders in %s') % (str(len(extracted)), format_time_string(time.time() - start)) nzo.set_unpack_info('Unpack', '[%s] %s' % (unicoder(setname), msg)) logging.info('%s', msg) return 0, extracted, rarfiles ############################################################################## # (Un)Zip Functions ############################################################################## def unzip(nzo, workdir, workdir_complete, delete, one_folder, zips): """ Unpack multiple sets 'zips' of ZIP files from 'workdir' to 'workdir_complete. When 'delete' is ste, originals will be deleted. """ try: i = 0 unzip_failed = False tms = time.time() for _zip in zips: logging.info("Starting extract on zipfile: %s ", _zip) nzo.set_action_line(T('Unpacking'), '%s' % unicoder(os.path.basename(_zip))) if workdir_complete and _zip.startswith(workdir): extraction_path = workdir_complete else: extraction_path = os.path.split(_zip)[0] if ZIP_Extract(_zip, extraction_path, one_folder): unzip_failed = True else: i += 1 msg = T('%s files in %s') % (str(i), format_time_string(time.time() - tms)) nzo.set_unpack_info('Unpack', msg) # Delete the old files if we have to if delete and not unzip_failed: i = 0 for _zip in zips: try: remove_file(_zip) i += 1 except OSError: logging.warning(T('Deleting %s failed!'), _zip) brokenzip = '%s.1' % _zip if os.path.exists(brokenzip): try: remove_file(brokenzip) i += 1 except OSError: logging.warning(T('Deleting %s failed!'), brokenzip) return unzip_failed except: msg = sys.exc_info()[1] nzo.fail_msg = T('Unpacking failed, %s') % msg logging.error(T('Error "%s" while running unzip() on %s'), msg, nzo.final_name) return True def ZIP_Extract(zipfile, extraction_path, one_folder): """ Unzip single zip set 'zipfile' to 'extraction_path' """ command = ['%s' % ZIP_COMMAND, '-o', '-Pnone', '%s' % clip_path(zipfile), '-d%s' % extraction_path] if one_folder or cfg.flat_unpack(): command.insert(3, '-j') # Unpack without folders stup, need_shell, command, creationflags = build_command(command) logging.debug('Starting unzip: %s', command) p = Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, creationflags=creationflags) output = p.stdout.read() logging.debug('unzip output: \n%s', output) ret = p.wait() return ret ############################################################################## # 7Zip Functions ############################################################################## def unseven(nzo, workdir, workdir_complete, delete, one_folder, sevens): """ Unpack multiple sets '7z' of 7Zip files from 'workdir' to 'workdir_complete. When 'delete' is set, originals will be deleted. """ i = 0 unseven_failed = False tms = time.time() # Find multi-volume sets, because 7zip will not provide actual set members sets = {} for seven in sevens: name, ext = os.path.splitext(seven) ext = ext.strip('.') if not ext.isdigit(): name = seven ext = None if name not in sets: sets[name] = [] if ext: sets[name].append(ext) # Unpack each set for seven in sets: extensions = sets[seven] logging.info("Starting extract on 7zip set/file: %s ", seven) nzo.set_action_line(T('Unpacking'), '%s' % unicoder(os.path.basename(seven))) if workdir_complete and seven.startswith(workdir): extraction_path = workdir_complete else: extraction_path = os.path.split(seven)[0] res, msg = seven_extract(nzo, seven, extensions, extraction_path, one_folder, delete) if res: unseven_failed = True nzo.set_unpack_info('Unpack', msg) else: i += 1 if not unseven_failed: msg = T('%s files in %s') % (str(i), format_time_string(time.time() - tms)) nzo.set_unpack_info('Unpack', msg) return unseven_failed def seven_extract(nzo, sevenset, extensions, extraction_path, one_folder, delete): """ Unpack single set 'sevenset' to 'extraction_path', with password tries Return fail==0(ok)/fail==1(error)/fail==2(wrong password), new_files, sevens """ fail = 0 passwords = get_all_passwords(nzo) for password in passwords: if password: logging.debug('Trying 7zip with password "%s"', password) msg = T('Trying 7zip with password "%s"') % unicoder(password) nzo.fail_msg = msg nzo.set_unpack_info('Unpack', msg) fail, msg = seven_extract_core(sevenset, extensions, extraction_path, one_folder, delete, password) if fail != 2: break nzo.fail_msg = '' if fail == 2: msg = '%s (%s)' % (T('Unpacking failed, archive requires a password'), os.path.basename(sevenset)) nzo.fail_msg = msg logging.error(msg) return fail, msg def seven_extract_core(sevenset, extensions, extraction_path, one_folder, delete, password): """ Unpack single 7Z set 'sevenset' to 'extraction_path' Return fail==0(ok)/fail==1(error)/fail==2(wrong password), message """ if one_folder: method = 'e' # Unpack without folders else: method = 'x' # Unpack with folders if sabnzbd.WIN32 or sabnzbd.DARWIN: case = '-ssc-' # Case insensitive else: case = '-ssc' # Case sensitive if cfg.overwrite_files(): overwrite = '-aoa' else: overwrite = '-aou' if password: password = '-p%s' % password else: password = '-p' if len(extensions) > 0: name = '%s.001' % sevenset parm = '-tsplit' else: name = sevenset parm = '-tzip' if sevenset.lower().endswith('.zip') else '-t7z' if not os.path.exists(name): return 1, T('7ZIP set "%s" is incomplete, cannot unpack') % unicoder(sevenset) command = [SEVEN_COMMAND, method, '-y', overwrite, parm, case, password, '-o%s' % extraction_path, name] stup, need_shell, command, creationflags = build_command(command) logging.debug('Starting 7za: %s', command) p = Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, creationflags=creationflags) output = p.stdout.read() logging.debug('7za output: %s', output) ret = p.wait() if ret == 0 and delete: if extensions: for ext in extensions: path = '%s.%s' % (sevenset, ext) try: remove_file(path) except: logging.warning(T('Deleting %s failed!'), path) else: try: remove_file(sevenset) except: logging.warning(T('Deleting %s failed!'), sevenset) # Always return an error message, even when return code is 0 return ret, T('Could not unpack %s') % unicoder(sevenset) ############################################################################## # PAR2 Functions ############################################################################## def par2_repair(parfile_nzf, nzo, workdir, setname, single): """ Try to repair a set, return readd or correctness """ # Check if file exists, otherwise see if another is done parfile_path = os.path.join(workdir, parfile_nzf.filename) if not os.path.exists(parfile_path) and nzo.extrapars[setname]: for new_par in nzo.extrapars[setname]: test_parfile = os.path.join(workdir, new_par.filename) if os.path.exists(test_parfile): parfile_nzf = new_par break else: # No file was found, we assume this set already finished return False, True parfile = os.path.join(workdir, parfile_nzf.filename) old_dir_content = os.listdir(workdir) used_joinables = () joinables = () used_for_repair = () result = readd = False # Need to copy now, gets pop-ed during repair setpars = nzo.extrapars[setname][:] # Start QuickCheck nzo.status = Status.QUICK_CHECK nzo.set_action_line(T('Repair'), T('Quick Checking')) qc_result = QuickCheck(setname, nzo) if qc_result: logging.info("Quick-check for %s is OK, skipping repair", setname) nzo.set_unpack_info('Repair', T('[%s] Quick Check OK') % unicoder(setname)) result = True if not result and cfg.enable_all_par(): # Download all par2 files that haven't been downloaded yet readd = False for extrapar in nzo.extrapars[setname][:]: # Make sure we only get new par2 files if extrapar not in nzo.finished_files and extrapar not in nzo.files: nzo.add_parfile(extrapar) readd = True if readd: return readd, result if not result: nzo.status = Status.REPAIRING result = False readd = False try: nzo.set_action_line(T('Repair'), T('Starting Repair')) logging.info('Scanning "%s"', parfile) joinables, zips, rars, sevens, ts = build_filelists(workdir, check_rar=False) # Multipar or not? if sabnzbd.WIN32 and cfg.multipar(): finished, readd, datafiles, used_joinables, used_for_repair = MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, single=single) else: finished, readd, datafiles, used_joinables, used_for_repair = PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, single=single) if finished: result = True logging.info('Par verify finished ok on %s!', parfile) # Remove this set so we don't try to check it again nzo.remove_parset(parfile_nzf.setname) else: if qc_result: logging.warning(T('Par verify failed on %s, while QuickCheck succeeded!'), parfile) else: logging.info('Par verify failed on %s!', parfile) if not readd: # Failed to repair -> remove this set nzo.remove_parset(parfile_nzf.setname) return readd, False except: msg = sys.exc_info()[1] nzo.fail_msg = T('Repairing failed, %s') % msg logging.error(T('Error %s while running par2_repair on set %s'), msg, setname) logging.info("Traceback: ", exc_info=True) return readd, result try: if cfg.enable_par_cleanup(): deletables = [] new_dir_content = os.listdir(workdir) # Remove extra files created during repair and par2 base files for path in new_dir_content: if os.path.splitext(path)[1] == '.1' and path not in old_dir_content: deletables.append(os.path.join(workdir, path)) deletables.append(os.path.join(workdir, setname + '.par2')) deletables.append(os.path.join(workdir, setname + '.PAR2')) deletables.append(parfile) # Add output of par2-repair to remove deletables.extend(used_joinables) deletables.extend([os.path.join(workdir, f) for f in used_for_repair]) # Delete pars of the set deletables.extend([os.path.join(workdir, nzf.filename) for nzf in setpars]) for filepath in deletables: if filepath in joinables: joinables.remove(filepath) if os.path.exists(filepath): try: remove_file(filepath) except OSError: logging.warning(T('Deleting %s failed!'), filepath) except: msg = sys.exc_info()[1] nzo.fail_msg = T('Repairing failed, %s') % msg logging.error(T('Error "%s" while running par2_repair on set %s'), msg, setname, exc_info=True) return readd, result _RE_BLOCK_FOUND = re.compile(r'File: "([^"]+)" - found \d+ of \d+ data blocks from "([^"]+)"') _RE_IS_MATCH_FOR = re.compile(r'File: "([^"]+)" - is a match for "([^"]+)"') _RE_LOADING_PAR2 = re.compile(r'Loading "([^"]+)"\.') _RE_LOADED_PAR2 = re.compile(r'Loaded (\d+) new packets') def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, single=False): """ Run par2 on par-set """ used_joinables = [] used_for_repair = [] # set the current nzo status to "Verifying...". Used in History nzo.status = Status.VERIFYING start = time.time() options = cfg.par_option().strip() command = [str(PAR2_COMMAND), 'r', options, parfile] # Append the wildcard for this set parfolder = os.path.split(parfile)[0] if single or len(globber(parfolder, setname + '*')) < 2: # Support bizarre naming conventions wildcard = '*' else: # Normal case, everything is named after set wildcard = setname + '*' if sabnzbd.WIN32 or sabnzbd.DARWIN: command.append(os.path.join(parfolder, wildcard)) else: # For Unix systems, remove folders, due to bug in some par2cmdline versions flist = [item for item in globber_full(parfolder, wildcard) if os.path.isfile(item)] command.extend(flist) # We need to check for the bad par2cmdline that skips blocks # Or the one that complains about basepath # Only if we're not doing multicore if not sabnzbd.WIN32 and not sabnzbd.DARWIN: par2text = run_simple([command[0], '-h']) if 'No data skipping' in par2text: logging.info('Detected par2cmdline version that skips blocks, adding -N parameter') command.insert(2, '-N') if 'Set the basepath' in par2text: logging.info('Detected par2cmdline version that needs basepath, adding -B parameter') command.insert(2, '-B') command.insert(3, parfolder) stup, need_shell, command, creationflags = build_command(command) # par2multicore wants to see \\.\ paths on Windows # See: https://github.com/sabnzbd/sabnzbd/pull/771 if sabnzbd.WIN32: command = [clip_path(x) if x.startswith('\\\\?\\') else x for x in command] # Run the external command logging.info('Starting par2: %s', command) lines = [] try: p = Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, creationflags=creationflags) proc = p.stdout if p.stdin: p.stdin.close() # Set up our variables datafiles = [] renames = {} reconstructed = [] linebuf = '' finished = 0 readd = False verifynum = 1 verifytotal = 0 verified = 0 in_verify_repaired = False # Loop over the output, whee while 1: char = proc.read(1) if not char: break # Line not complete yet if char not in ('\n', '\r'): linebuf += char continue line = linebuf.strip() linebuf = '' # Check if we should still continue if not nzo.pp_active: p.kill() msg = T('PostProcessing was aborted (%s)') % T('Repair') nzo.fail_msg = msg nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED readd = False break # Skip empty lines if line == '': continue if 'Repairing:' not in line: lines.append(line) if line.startswith(('Invalid option specified', 'Invalid thread option', 'Cannot specify recovery file count')): msg = T('[%s] PAR2 received incorrect options, check your Config->Switches settings') % unicoder(setname) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED logging.error(msg) elif line.startswith('All files are correct'): msg = T('[%s] Verified in %s, all files correct') % (unicoder(setname), format_time_string(time.time() - start)) nzo.set_unpack_info('Repair', msg) logging.info('Verified in %s, all files correct', format_time_string(time.time() - start)) finished = 1 elif line.startswith('Repair is required'): msg = T('[%s] Verified in %s, repair is required') % (unicoder(setname), format_time_string(time.time() - start)) nzo.set_unpack_info('Repair', msg) logging.info('Verified in %s, repair is required', format_time_string(time.time() - start)) start = time.time() verified = 1 # Reset to use them again for verification of repair verifytotal = 0 verifynum = 0 elif line.startswith('Main packet not found') or 'The recovery file does not exist' in line: # Initialparfile probably didn't decode properly or bad user parameters # We will try to get another par2 file, but 99% of time it's user parameters msg = T('Invalid par2 files or invalid PAR2 parameters, cannot verify or repair') logging.info(msg) logging.info("Extra pars = %s", nzo.extrapars[setname]) # Look for the smallest par2file block_table = {} for nzf in nzo.extrapars[setname]: if not nzf.completed: block_table[int_conv(nzf.blocks)] = nzf if block_table: nzf = block_table[min(block_table.keys())] logging.info("Found new par2file %s", nzf.filename) # Move from extrapar list to files to be downloaded # and remove it from the extrapars list nzo.add_parfile(nzf) readd = True else: nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED elif line.startswith('You need'): # We need more blocks, but are they available? chunks = line.split() needed_blocks = int(chunks[2]) # Check if we have enough blocks added_blocks = nzo.get_extra_blocks(setname, needed_blocks) if added_blocks: msg = T('Fetching %s blocks...') % str(added_blocks) nzo.set_action_line(T('Fetching'), msg) readd = True else: # Failed msg = T('Repair failed, not enough repair blocks (%s short)') % str(needed_blocks) nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED elif line.startswith('Repair is possible'): start = time.time() nzo.set_action_line(T('Repairing'), '%2d%%' % (0)) elif line.startswith('Repairing:'): chunks = line.split() per = float(chunks[-1][:-1]) nzo.set_action_line(T('Repairing'), '%2d%%' % per) nzo.status = Status.REPAIRING elif line.startswith('Repair complete'): msg = T('[%s] Repaired in %s') % (unicoder(setname), format_time_string(time.time() - start)) nzo.set_unpack_info('Repair', msg) logging.info('Repaired in %s', format_time_string(time.time() - start)) finished = 1 elif verified and line.endswith(('are missing.', 'exist but are damaged.')): # Files that will later be verified after repair chunks = line.split() verifytotal += int(chunks[0]) elif line.startswith('Verifying repaired files'): in_verify_repaired = True nzo.set_action_line(T('Verifying repair'), '%02d/%02d' % (verifynum, verifytotal)) elif in_verify_repaired and line.startswith('Target'): verifynum += 1 if verifynum <= verifytotal: nzo.set_action_line(T('Verifying repair'), '%02d/%02d' % (verifynum, verifytotal)) elif line.startswith('File:') and line.find('data blocks from') > 0: m = _RE_BLOCK_FOUND.search(line) if m: workdir = os.path.split(parfile)[0] old_name = TRANS(m.group(1)) new_name = TRANS(m.group(2)) if joinables: # Find out if a joinable file has been used for joining uline = unicoder(line) for jn in joinables: if uline.find(os.path.split(jn)[1]) > 0: used_joinables.append(jn) break # Special case of joined RAR files, the "of" and "from" must both be RAR files # This prevents the joined rars files from being seen as an extra rar-set if '.rar' in old_name.lower() and '.rar' in new_name.lower(): used_joinables.append(os.path.join(workdir, old_name)) else: logging.debug('PAR2 will reconstruct "%s" from "%s"', new_name, old_name) reconstructed.append(os.path.join(workdir, old_name)) elif 'Could not write' in line and 'at offset 0:' in line: # If there are joinables, this error will only happen in case of 100% complete files # We can just skip the retry, because par2cmdline will fail in those cases # becauses it refuses to scan the ".001" file if joinables: finished = 1 used_joinables = [] elif ' cannot be renamed to ' in line: msg = unicoder(line.strip()) nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED elif 'There is not enough space on the disk' in line: # Oops, disk is full! msg = T('Repairing failed, %s') % T('Disk full') nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED # File: "oldname.rar" - is a match for "newname.rar". elif 'is a match for' in line: m = _RE_IS_MATCH_FOR.search(line) if m: old_name = TRANS(m.group(1)) new_name = TRANS(m.group(2)) logging.debug('PAR2 will rename "%s" to "%s"', old_name, new_name) renames[new_name] = old_name # Show progress if verifytotal == 0 or verifynum < verifytotal: verifynum += 1 nzo.set_action_line(T('Verifying'), '%02d/%02d' % (verifynum, verifytotal)) elif 'Scanning extra files' in line: # Obfuscated post most likely, so reset counter to show progress verifynum = 1 elif 'No details available for recoverable file' in line: msg = unicoder(line.strip()) nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED elif line.startswith('Repair Failed.'): # Unknown repair problem msg = T('Repairing failed, %s') % line nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED finished = 0 elif not verified: if line.startswith('Verifying source files'): nzo.set_action_line(T('Verifying'), '01/%02d' % verifytotal) nzo.status = Status.VERIFYING elif line.startswith('Scanning:'): pass # Target files m = TARGET_RE.match(line) if m: nzo.status = Status.VERIFYING verifynum += 1 if verifytotal == 0 or verifynum < verifytotal: nzo.set_action_line(T('Verifying'), '%02d/%02d' % (verifynum, verifytotal)) else: nzo.set_action_line(T('Checking extra files'), '%02d' % verifynum) # Remove redundant extra files that are just duplicates of original ones if 'duplicate data blocks' in line: used_for_repair.append(TRANS(m.group(1))) else: datafiles.append(TRANS(m.group(1))) continue # Verify done m = re.match(r'There are (\d+) recoverable files', line) if m: verifytotal = int(m.group(1)) p.wait() except WindowsError, err: raise WindowsError(err) # Also log what is shown to user in history if nzo.fail_msg: logging.info(nzo.fail_msg) logging.debug('PAR2 output was\n%s', '\n'.join(lines)) # If successful, add renamed files to the collection if finished and renames: nzo.renamed_file(renames) # If successful and files were reconstructed, remove incomplete original files if finished and reconstructed: # Use 'used_joinables' as a vehicle to get rid of the files used_joinables.extend(reconstructed) return finished, readd, datafiles, used_joinables, used_for_repair _RE_FILENAME = re.compile(r'"([^"]+)"') def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, single=False): """ Run par2 on par-set """ parfolder = os.path.split(parfile)[0] used_joinables = [] used_for_repair = [] # set the current nzo status to "Verifying...". Used in History nzo.status = Status.VERIFYING start = time.time() # Caching of verification implemented by adding: # But not really required due to prospective-par2 command = [str(MULTIPAR_COMMAND), 'r', '-vs2', '-vd%s' % parfolder, parfile] # Check if there are maybe par2cmdline/par2tbb commands supplied if '-t' in cfg.par_option() or '-p' in cfg.par_option(): logging.info('Removing old par2cmdline/par2tbb options for MultiPar') cfg.par_option.set('') # Only add user-options if supplied options = cfg.par_option().strip() if options: # We wrongly instructed users to use /x parameter style instead of -x options = options.replace('/', '-', 1) command.insert(2, options) # Append the wildcard for this set if single or len(globber(parfolder, setname + '*')) < 2: # Support bizarre naming conventions wildcard = '*' else: # Normal case, everything is named after set wildcard = setname + '*' command.append(os.path.join(parfolder, wildcard)) stup, need_shell, command, creationflags = build_command(command) logging.info('Starting MultiPar: %s', command) lines = [] p = Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, creationflags=creationflags) proc = p.stdout if p.stdin: p.stdin.close() # Set up our variables datafiles = [] renames = {} reconstructed = [] linebuf = '' finished = 0 readd = False verifynum = 0 verifytotal = 0 in_check = False in_verify = False in_repair = False in_verify_repaired = False misnamed_files = False old_name = None # Loop over the output, whee while 1: char = proc.read(1) if not char: break # Line not complete yet if char not in ('\n', '\r'): linebuf += char continue line = linebuf.strip() linebuf = '' # Check if we should still continue if not nzo.pp_active: p.kill() msg = T('PostProcessing was aborted (%s)') % T('Repair') nzo.fail_msg = msg nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED readd = False break # Skip empty lines if line == '': continue # Save it all lines.append(line) # ----------------- Startup if line.startswith('invalid option'): # Option error msg = T('[%s] PAR2 received incorrect options, check your Config->Switches settings') % unicoder(setname) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED logging.error(msg) elif line.startswith('valid file is not found'): # Initialparfile probably didn't decode properly, or bad user parameters # We will try to get another par2 file, but 99% of time it's user parameters msg = T('Invalid par2 files or invalid PAR2 parameters, cannot verify or repair') logging.info(msg) logging.info("Extra pars = %s", nzo.extrapars[setname]) # Look for the smallest par2file block_table = {} for nzf in nzo.extrapars[setname]: if not nzf.completed: block_table[int_conv(nzf.blocks)] = nzf if block_table: nzf = block_table[min(block_table.keys())] logging.info("Found new par2file %s", nzf.filename) # Move from extrapar list to files to be downloaded # and remove it from the extrapars list nzo.add_parfile(nzf) readd = True else: nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED elif line.startswith('There is not enough space on the disk'): msg = T('Repairing failed, %s') % T('Disk full') nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED # ----------------- Start check/verify stage elif line.startswith('Recovery Set ID'): # Remove files were MultiPar stores verification result when repaired succesfull recovery_id = line.split()[-1] used_for_repair.append('2_%s.bin' % recovery_id) used_for_repair.append('2_%s.ini' % recovery_id) elif line.startswith('Input File total count'): # How many files will it try to find? verifytotal = int(line.split()[-1]) # ----------------- Misnamed-detection stage # Misnamed files elif line.startswith('Searching misnamed file'): # We are in the misnamed files block misnamed_files = True verifynum = 0 elif misnamed_files and 'Found' in line: # First it reports the current filename m = _RE_FILENAME.search(line) if m: verifynum += 1 nzo.set_action_line(T('Checking'), '%02d/%02d' % (verifynum, verifytotal)) old_name = TRANS(m.group(1)) elif misnamed_files and 'Misnamed' in line: # Then it finds the actual m = _RE_FILENAME.search(line) if m and old_name: new_name = TRANS(m.group(1)) logging.debug('MultiPar will rename "%s" to "%s"', old_name, new_name) renames[new_name] = old_name # New name is also part of data! datafiles.append(new_name) reconstructed.append(old_name) # ----------------- Checking stage # Checking input files elif line.startswith('Complete file count'): in_check = False verifynum = 0 old_name = None elif line.startswith('Verifying Input File'): in_check = True nzo.status = Status.VERIFYING elif in_check: m = _RE_FILENAME.search(line) if m: # Only increase counter if it was really the detection line if line.startswith('= ') or '%' not in line: verifynum += 1 nzo.set_action_line(T('Checking'), '%02d/%02d' % (verifynum, verifytotal)) old_name = TRANS(m.group(1)) # ----------------- Verify stage # Which files need extra verification? elif line.startswith('Damaged file count'): verifytotal = int(line.split()[-1]) elif line.startswith('Missing file count'): verifytotal += int(line.split()[-1]) # Actual verification elif line.startswith('Input File Slice found'): # End of verification AND end of misnamed file search in_verify = False misnamed_files = False old_name = None elif line.startswith('Finding available slice'): # The actual scanning of the files in_verify = True nzo.set_action_line(T('Verifying'), T('Checking')) elif in_verify: m = _RE_FILENAME.search(line) if m: # It prints the filename couple of times, so we save it to check # 'datafiles' will not contain all data-files in par-set, only the # ones that got scanned, but it's ouput is never used! nzo.status = Status.VERIFYING if line.split()[1] in ('Damaged', 'Found'): verifynum += 1 datafiles.append(TRANS(m.group(1))) # Set old_name in case it was misnamed and found (not when we are joining) old_name = None if line.split()[1] == 'Found' and not joinables: old_name = TRANS(m.group(1)) # Sometimes we don't know the total (filejoin) if verifytotal <= 1: nzo.set_action_line(T('Verifying'), '%02d' % verifynum) else: nzo.set_action_line(T('Verifying'), '%02d/%02d' % (verifynum, verifytotal)) elif old_name and old_name != TRANS(m.group(1)): # Hey we found another misnamed one! new_name = TRANS(m.group(1)) logging.debug('MultiPar will rename "%s" to "%s"', old_name, new_name) renames[new_name] = old_name # Put it back with it's new name! datafiles.pop() datafiles.append(new_name) # Need to remove the old file after repair (Multipar keeps it) used_for_repair.append(old_name) # Need to reset it to avoid collision old_name = None else: # It's scanning extra files that don't belong to the set # For damaged files it reports the filename twice, so only then start verifynum += 1 if verifynum / 2 > verifytotal: nzo.set_action_line(T('Checking extra files'), '%02d' % verifynum) if joinables: # Find out if a joinable file has been used for joining uline = unicoder(line) for jn in joinables: if uline.find(os.path.split(jn)[1]) > 0: used_joinables.append(jn) datafiles.append(TRANS(m.group(1))) break elif line.startswith('Need'): # We need more blocks, but are they available? chunks = line.split() needed_blocks = int(chunks[1]) # Check if we have enough blocks added_blocks = nzo.get_extra_blocks(setname, needed_blocks) if added_blocks: msg = T('Fetching %s blocks...') % str(added_blocks) nzo.set_action_line(T('Fetching'), msg) readd = True else: # Failed msg = T('Repair failed, not enough repair blocks (%s short)') % str(needed_blocks) nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED # MultiPar can say 'PAR File(s) Incomplete' also when it needs more blocks # But the Need-more-blocks message is always last, so force failure finished = 0 # Result of verification elif line.startswith('All Files Complete') or line.endswith('PAR File(s) Incomplete'): # Completed without damage! # 'PAR File(s) Incomplete' is reported for success # but when there are very similar filenames in the folder msg = T('[%s] Verified in %s, all files correct') % (unicoder(setname), format_time_string(time.time() - start)) nzo.set_unpack_info('Repair', msg) logging.info('Verified in %s, all files correct', format_time_string(time.time() - start)) finished = 1 elif line.startswith(('Ready to repair', 'Ready to rejoin')): # Ready to repair! # Or we are re-joining a split file when there's no damage but takes time msg = T('[%s] Verified in %s, repair is required') % (unicoder(setname), format_time_string(time.time() - start)) nzo.set_unpack_info('Repair', msg) logging.info('Verified in %s, repair is required', format_time_string(time.time() - start)) start = time.time() # Set message for user in case of joining if line.startswith('Ready to rejoin'): nzo.set_action_line(T('Joining'), '%2d' % len(used_joinables)) # ----------------- Repair stage elif 'Recovering slice' in line: # Before this it will calculate matrix, here is where it starts start = time.time() in_repair = True nzo.set_action_line(T('Repairing'), '%2d%%' % (0)) elif in_repair and line.startswith('Verifying repair'): in_repair = False in_verify_repaired = True # How many will be checked? verifytotal = int(line.split()[-1]) verifynum = 0 elif in_repair: # Line with percentage of repair (nothing else) per = float(line[:-1]) nzo.set_action_line(T('Repairing'), '%2d%%' % per) nzo.status = Status.REPAIRING elif line.startswith('Repaired successfully'): msg = T('[%s] Repaired in %s') % (unicoder(setname), format_time_string(time.time() - start)) nzo.set_unpack_info('Repair', msg) logging.info('Repaired in %s', format_time_string(time.time() - start)) finished = 1 elif in_verify_repaired and line.startswith('Repaired :'): # Track verification of repaired files (can sometimes take a while) verifynum += 1 nzo.set_action_line(T('Verifying repair'), '%02d/%02d' % (verifynum, verifytotal)) elif line.startswith('Failed to repair'): # Unknown repair problem msg = T('Repairing failed, %s') % line nzo.fail_msg = msg msg = u'[%s] %s' % (unicoder(setname), msg) nzo.set_unpack_info('Repair', msg) nzo.status = Status.FAILED finished = 0 p.wait() # Also log what is shown to user in history if nzo.fail_msg: logging.info(nzo.fail_msg) logging.debug('MultiPar output was\n%s', '\n'.join(lines)) # Add renamed files to the collection # MultiPar always(!!) renames automatically whatever it can in the 'Searching misnamed file:'-section # Even if the repair did not complete fully it will rename those! # But the ones in 'Finding available slices'-section will only be renamed after succesfull repair if renames: # If succes, we also remove the possibly previously renamed ones if finished: reconstructed.extend(renames.values()) # Adding to the collection nzo.renamed_file(renames) # Remove renamed original files workdir = os.path.split(parfile)[0] used_joinables.extend([os.path.join(workdir, name) for name in reconstructed]) return finished, readd, datafiles, used_joinables, used_for_repair def create_env(nzo=None, extra_env_fields=None): """ Modify the environment for pp-scripts with extra information OSX: Return copy of environment without PYTHONPATH and PYTHONHOME other: return None """ env = os.environ.copy() # Are we adding things? if nzo: # Add basic info for field in ENV_NZO_FIELDS: try: field_value = getattr(nzo, field) # Special filters for Python types if field_value is None: env['SAB_' + field.upper()] = '' elif isinstance(field_value, bool): env['SAB_' + field.upper()] = str(field_value*1) else: env['SAB_' + field.upper()] = field_value except: # Catch key/unicode errors pass # Add extra fields for field in extra_env_fields: try: if extra_env_fields[field] is not None: env['SAB_' + field.upper()] = extra_env_fields[field] else: env['SAB_' + field.upper()] = '' except: # Catch key/unicode errors pass if sabnzbd.DARWIN: if 'PYTHONPATH' in env: del env['PYTHONPATH'] if 'PYTHONHOME' in env: del env['PYTHONHOME'] elif not nzo: # No modification return None # Have to make sure no Unicode slipped in somehow env = { deunicode(k): deunicode(v) for k, v in env.iteritems() } return env def userxbit(filename): # Returns boolean if the x-bit for user is set on the given file # This is a workaround: os.access(filename, os.X_OK) does not work on certain mounted file systems # Does not work on Windows, but it is not called on Windows # rwx rwx rwx # 876 543 210 # we want bit 6 from the right, counting from 0 userxbit = 1<<6 # bit 6 rwxbits = os.stat(filename)[0] # the first element of os.stat() is "mode" # do logical AND, check if it is not 0: xbitset = (rwxbits & userxbit) > 0 return xbitset def build_command(command, flatten_command=False): """ Prepare list from running an external program On Windows we need to run our own list2cmdline for Unrar """ if not sabnzbd.WIN32: if command[0].endswith('.py'): with open(command[0], 'r') as script_file: if not userxbit(command[0]): # Inform user that Python scripts need x-bit and then stop logging.error(T('Python script "%s" does not have execute (+x) permission set'), command[0]) raise IOError elif script_file.read(2) != '#!': # No shebang (#!) defined, add default python command.insert(0, 'python') if IONICE_COMMAND and cfg.ionice().strip(): lst = cfg.ionice().split() lst.reverse() for arg in lst: command.insert(0, arg) command.insert(0, IONICE_COMMAND) if NICE_COMMAND and cfg.nice().strip(): lst = cfg.nice().split() lst.reverse() for arg in lst: command.insert(0, arg) command.insert(0, NICE_COMMAND) need_shell = False stup = None creationflags = 0 else: # For Windows we always need to add python interpreter if command[0].endswith('.py'): command.insert(0, 'python') need_shell = os.path.splitext(command[0])[1].lower() not in ('.exe', '.com') stup = subprocess.STARTUPINFO() stup.dwFlags = STARTF_USESHOWWINDOW stup.wShowWindow = SW_HIDE creationflags = IDLE_PRIORITY_CLASS # Work-around for bug in Python's Popen function, # scripts with spaces in the path don't work. if need_shell and ' ' in command[0]: command[0] = win32api.GetShortPathName(command[0]) if need_shell or flatten_command: command = list2cmdline(command) return stup, need_shell, command, creationflags def rar_volumelist(rarfile_path, password, known_volumes): """ Extract volumes that are part of this rarset and merge them with existing list, removing duplicates """ # UnRar is required to read some RAR files # RarFile can fail in special cases try: rarfile.UNRAR_TOOL = RAR_COMMAND zf = rarfile.RarFile(rarfile_path) # setpassword can fail due to bugs in RarFile if password: try: zf.setpassword(password) except: pass zf_volumes = zf.volumelist() except: zf_volumes = [] # Remove duplicates known_volumes_base = [os.path.basename(vol) for vol in known_volumes] for zf_volume in zf_volumes: if os.path.basename(zf_volume) not in known_volumes_base: # Long-path notation just to be sure known_volumes.append(long_path(zf_volume)) return known_volumes # Sort the various RAR filename formats properly :\ def rar_sort(a, b): """ Define sort method for rar file names """ aext = a.split('.')[-1] bext = b.split('.')[-1] if aext == 'rar' and bext == 'rar': return cmp(a, b) elif aext == 'rar': return -1 elif bext == 'rar': return 1 else: return cmp(a, b) def build_filelists(workdir, workdir_complete=None, check_both=False, check_rar=True): """ Build filelists, if workdir_complete has files, ignore workdir. Optionally scan both directories. Optionally test content to establish RAR-ness """ sevens, joinables, zips, rars, ts, filelist = ([], [], [], [], [], []) if workdir_complete: for root, dirs, files in os.walk(workdir_complete): for _file in files: if '.AppleDouble' not in root and '.DS_Store' not in root: try: p = os.path.join(root, _file) filelist.append(p) except UnicodeDecodeError: # Just skip failing names pass if workdir and (not filelist or check_both): for root, dirs, files in os.walk(workdir): for _file in files: if '.AppleDouble' not in root and '.DS_Store' not in root: try: p = os.path.join(root, _file) filelist.append(p) except UnicodeDecodeError: # Just skip failing names pass for file in filelist: # Extra check for rar (takes CPU/disk) file_is_rar = False if check_rar: try: # Can fail on Windows due to long-path after recursive-unpack file_is_rar = rarfile.is_rarfile(file) except: pass # Run through all the checks if SEVENZIP_RE.search(file) or SEVENMULTI_RE.search(file): # 7zip sevens.append(file) elif SPLITFILE_RE.search(file) and not file_is_rar: # Joinables, optional with RAR check joinables.append(file) elif ZIP_RE.search(file): # ZIP files zips.append(file) elif RAR_RE.search(file): # RAR files rars.append(file) elif TS_RE.search(file): # TS split files ts.append(file) logging.debug("build_filelists(): joinables: %s", joinables) logging.debug("build_filelists(): zips: %s", zips) logging.debug("build_filelists(): rars: %s", rars) logging.debug("build_filelists(): 7zips: %s", sevens) logging.debug("build_filelists(): ts: %s", ts) return joinables, zips, rars, sevens, ts def QuickCheck(set, nzo): """ Check all on-the-fly md5sums of a set """ md5pack = nzo.md5packs.get(set) if md5pack is None: return False # We use bitwise assigment (&=) so False always wins in case of failure # This way the renames always get saved! result = True nzf_list = nzo.finished_files renames = {} # Files to ignore ignore_ext = cfg.quick_check_ext_ignore() for file in md5pack: found = False file_platform = platform_encode(file) file_to_ignore = os.path.splitext(file_platform)[1].lower().replace('.', '') in ignore_ext for nzf in nzf_list: # Do a simple filename based check if file_platform == nzf.filename: found = True if (nzf.md5sum is not None) and nzf.md5sum == md5pack[file]: logging.debug('Quick-check of file %s OK', file) result &= True elif file_to_ignore: # We don't care about these files logging.debug('Quick-check ignoring file %s', file) result &= True else: logging.info('Quick-check of file %s failed!', file) result = False break # Now lets do obfuscation check if nzf.md5sum == md5pack[file]: try: logging.debug('Quick-check will rename %s to %s', nzf.filename, file_platform) renamer(os.path.join(nzo.downpath, nzf.filename), os.path.join(nzo.downpath, file_platform)) renames[file_platform] = nzf.filename nzf.filename = file_platform result &= True found = True break except IOError: # Renamed failed for some reason, probably already done break if not found: if file_to_ignore: # We don't care about these files logging.debug('Quick-check ignoring missing file %s', file) continue logging.info('Cannot Quick-check missing file %s!', file) result = False # Save renames if renames: nzo.renamed_file(renames) return result def unrar_check(rar): """ Return version number of unrar, where "5.01" returns 501 Also return whether an original version is found (version, original) """ version = 0 original = '' if rar: try: version = run_simple(rar) except: return version, original original = "Alexander Roshal" in version m = re.search(r"RAR\s(\d+)\.(\d+)", version) if m: version = int(m.group(1)) * 100 + int(m.group(2)) else: version = 0 return version, original def par2_mt_check(par2_path): """ Detect if we have multicore par2 variants """ try: par2_version = run_simple([par2_path, '-h']) # Look for a threads option if '-t<' in par2_version: return True except: pass return False def sfv_check(sfv_path): """ Verify files using SFV file, input: full path of sfv, file are assumed to be relative to sfv returns: List of failing files or [] when all is OK """ failed = [] try: fp = open(sfv_path, 'r') except: logging.info('Cannot open SFV file %s', sfv_path) failed.append(unicoder(sfv_path)) return failed root = os.path.split(sfv_path)[0] for line in fp: line = line.strip('\n\r ') if line and line[0] != ';': x = line.rfind(' ') if x > 0: filename = platform_encode(line[:x].strip()) checksum = line[x:].strip() path = os.path.join(root, filename) if os.path.exists(path): if crc_check(path, checksum): logging.debug('File %s passed SFV check', path) else: logging.info('File %s did not pass SFV check', path) failed.append(unicoder(filename)) else: logging.info('File %s missing in SFV check', path) failed.append(unicoder(filename)) fp.close() return failed def crc_check(path, target_crc): """ Return True if file matches CRC """ try: fp = open(path, 'rb') except: return False crc = binascii.crc32('') while 1: data = fp.read(4096) if not data: break crc = binascii.crc32(data, crc) fp.close() crc = '%08x' % (crc & 0xffffffff,) return crc.lower() == target_crc.lower() def analyse_show(name): """ Do a quick SeasonSort check and return basic facts """ job = SeriesSorter(None, name, None, None) job.match(force=True) if job.is_match(): job.get_values() info = job.show_info show_name = info.get('show_name', '').replace('.', ' ').replace('_', ' ') show_name = show_name.replace(' ', ' ') return show_name, \ info.get('season_num', ''), \ info.get('episode_num', ''), \ info.get('ep_name', '') def pre_queue(name, pp, cat, script, priority, size, groups): """ Run pre-queue script (if any) and process results """ def fix(p): if not p or str(p).lower() == 'none': return '' return unicoder(p) values = [1, name, pp, cat, script, priority, None] script_path = make_script_path(cfg.pre_script()) if script_path: command = [script_path, name, pp, cat, script, priority, str(size), ' '.join(groups)] command.extend(analyse_show(name)) command = [fix(arg) for arg in command] try: stup, need_shell, command, creationflags = build_command(command) env = create_env() logging.info('Running pre-queue script %s', command) p = Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, env=env, creationflags=creationflags) except: logging.debug("Failed script %s, Traceback: ", script_path, exc_info=True) return values output = p.stdout.read() ret = p.wait() logging.info('Pre-queue script returns %s and output=\n%s', ret, output) if ret == 0: n = 0 for line in output.split('\n'): line = line.strip('\r\n \'"') if n < len(values) and line: values[n] = deunicode(line) n += 1 accept = int_conv(values[0]) if accept < 1: logging.info('Pre-Q refuses %s', name) elif accept == 2: logging.info('Pre-Q accepts&fails %s', name) else: logging.info('Pre-Q accepts %s', name) return values def list2cmdline(lst): """ convert list to a cmd.exe-compatible command string """ nlst = [] for arg in lst: if not arg: nlst.append('""') else: nlst.append('"%s"' % arg) return ' '.join(nlst) def is_sevenfile(path): """ Return True if path has proper extension and 7Zip is installed """ return SEVEN_COMMAND and os.path.splitext(path)[1].lower() == '.7z' class SevenZip(object): """ Minimal emulation of ZipFile class for 7Zip """ def __init__(self, path): self.path = path def namelist(self): """ Return list of names in 7Zip """ names = [] # Future extension: use '-sccUTF-8' to get names in UTF8 encoding command = [SEVEN_COMMAND, 'l', '-p', '-y', '-slt', self.path] stup, need_shell, command, creationflags = build_command(command) p = Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, creationflags=creationflags) output = p.stdout.read() _ = p.wait() re_path = re.compile('^Path = (.+)') for line in output.split('\n'): m = re_path.search(line) if m: names.append(m.group(1).strip('\r')) if names: # Remove name of archive itself del names[0] return names def read(self, name): """ Read named file from 7Zip and return data """ command = [SEVEN_COMMAND, 'e', '-p', '-y', '-so', self.path, name] stup, need_shell, command, creationflags = build_command(command) # Ignore diagnostic output, otherwise it will be appended to content if sabnzbd.WIN32: stderr = open('nul', 'w') else: stderr = open('/dev/null', 'w') p = Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr, startupinfo=stup, creationflags=creationflags) output = p.stdout.read() _ = p.wait() stderr.close() return output def close(self): """ Close file """ pass def run_simple(cmd): """ Run simple external command and return output """ p = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) txt = p.stdout.read() p.wait() return txt SABnzbd-2.3.2/sabnzbd/newswrapper.py0000644000000000000000000004553013217005257015512 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.newswrapper """ import errno import socket from threading import Thread from nntplib import NNTPPermanentError import time import logging import re import ssl import sabnzbd from sabnzbd.constants import * import sabnzbd.cfg from sabnzbd.misc import nntp_to_msg # Have to make errors available under Python <2.7.9 if sabnzbd.HAVE_SSL_CONTEXT: WantReadError = ssl.SSLWantReadError CertificateError = ssl.CertificateError else: WantReadError = ssl.SSLError CertificateError = ssl.SSLError # Set pre-defined socket timeout socket.setdefaulttimeout(DEF_TIMEOUT) # getaddrinfo() can be very slow. In some situations this can lead # to delayed starts and timeouts on connections. # Because of this, the results will be cached in the server object. def _retrieve_info(server): """ Async attempt to run getaddrinfo() for specified server """ info = GetServerParms(server.host, server.port) if info is None: server.bad_cons += server.threads else: server.bad_cons = 0 (server.info, server.request) = (info, False) sabnzbd.downloader.Downloader.do.wakeup() def request_server_info(server): """ Launch async request to resolve server address """ if not server.request: server.request = True Thread(target=_retrieve_info, args=(server,)).start() def GetServerParms(host, port): """ Return processed getaddrinfo() for server """ try: int(port) except: port = 119 opt = sabnzbd.cfg.ipv6_servers() ''' ... with the following meaning for 'opt': Control the use of IPv6 Usenet server addresses. Meaning: 0 = don't use 1 = use when available and reachable (DEFAULT) 2 = force usage (when SABnzbd's detection fails) ''' try: # Standard IPV4 or IPV6 ips = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) if opt == 2 or (opt == 1 and sabnzbd.EXTERNAL_IPV6) or (opt == 1 and sabnzbd.cfg.load_balancing() == 2): # IPv6 forced by user, or IPv6 allowed and reachable, or IPv6 allowed and loadbalancing-with-IPv6 activated # So return all IP addresses, no matter IPv4 or IPv6: return ips else: # IPv6 unreachable or not allowed by user, so only return IPv4 address(es): return [ip for ip in ips if ':' not in ip[4][0]] except: if opt == 2 or (opt == 1 and sabnzbd.EXTERNAL_IPV6) or (opt == 1 and sabnzbd.cfg.load_balancing() == 2): try: # Try IPV6 explicitly return socket.getaddrinfo(host, port, socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_IP, socket.AI_CANONNAME) except: # Nothing found! pass return None def get_ssl_version(sock): # Python <2.7.9 doesn't have SSLConnection.version() try: return sock.version() except: # We can only give an estimation from the cipher return sock.cipher()[1] def con(sock, host, port, sslenabled, write_fds, nntp): try: sock.connect((host, port)) sock.setblocking(0) if sslenabled: # Log SSL/TLS info logging.info("%s@%s: Connected using %s (%s)", nntp.nw.thrdnum, nntp.nw.server.host, get_ssl_version(sock), sock.cipher()[0]) nntp.nw.server.ssl_info = "%s (%s)" % (get_ssl_version(sock), sock.cipher()[0]) # Now it's safe to add the socket to the list of active sockets. # 'write_fds' is an attribute of the Downloader singleton. # This direct access is needed to prevent multi-threading sync problems. if write_fds is not None: write_fds[sock.fileno()] = nntp.nw except (ssl.SSLError, CertificateError) as e: nntp.error(e) except socket.error, e: try: # socket.error can either return a string or a tuple if isinstance(e, tuple): (_errno, strerror) = e else: # Are we safe to hardcode the ETIMEDOUT error? (_errno, strerror) = (errno.ETIMEDOUT, str(e)) e = (_errno, strerror) # expected, do nothing if _errno == errno.EINPROGRESS: pass finally: nntp.error(e) def probablyipv4(ip): if ip.count('.') == 3 and re.sub('[0123456789.]', '', ip) == '': return True else: return False def probablyipv6(ip): if ip.count(':') >= 2 and re.sub('[0123456789abcdefABCDEF:]', '', ip) == '': return True else: return False class NNTP(object): # Pre-define attributes to save memory __slots__ = ('host', 'port', 'nw', 'blocking', 'error_msg', 'sock') def __init__(self, host, port, info, sslenabled, send_group, nw, user=None, password=None, block=False, write_fds=None): self.host = host self.port = port self.nw = nw self.blocking = block self.error_msg = None if not info: if block: info = GetServerParms(host, port) else: raise socket.error(errno.EADDRNOTAVAIL, "Address not available - Check for internet or DNS problems") af, socktype, proto, canonname, sa = info[0] # there will be a connect to host (or self.host, so let's force set 'af' to the correct value if probablyipv4(host): af = socket.AF_INET if probablyipv6(host): af = socket.AF_INET6 if sslenabled: # Use context or just wrapper if sabnzbd.HAVE_SSL_CONTEXT: # Setup the SSL socket ctx = ssl.create_default_context() # Only verify hostname when we're strict if(nw.server.ssl_verify < 2): ctx.check_hostname = False # Certificates optional if(nw.server.ssl_verify == 0): ctx.verify_mode = ssl.CERT_NONE # Did the user set a custom cipher-string? if(sabnzbd.cfg.ssl_ciphers()): # At their own risk, socket will error out in case it was invalid ctx.set_ciphers(sabnzbd.cfg.ssl_ciphers()) self.sock = ctx.wrap_socket(socket.socket(af, socktype, proto), server_hostname=str(nw.server.host)) else: # Ciphers have to be None, if set to empty-string it will fail on <2.7.9 ciphers = sabnzbd.cfg.ssl_ciphers() if sabnzbd.cfg.ssl_ciphers() else None # Use a regular wrapper, no certificate validation self.sock = ssl.wrap_socket(socket.socket(af, socktype, proto), ciphers=ciphers) else: self.sock = socket.socket(af, socktype, proto) try: # Open the connection in a separate thread due to avoid blocking # For server-testing we do want blocking if not block: Thread(target=con, args=(self.sock, self.host, self.port, sslenabled, write_fds, self)).start() else: # if blocking (server test) only wait for 15 seconds during connect until timeout self.sock.settimeout(15) self.sock.connect((self.host, self.port)) if sslenabled: # Log SSL/TLS info logging.info("%s@%s: Connected using %s (%s)", self.nw.thrdnum, self.nw.server.host, get_ssl_version(self.sock), self.sock.cipher()[0]) self.nw.server.ssl_info = "%s (%s)" % (get_ssl_version(self.sock), self.sock.cipher()[0]) except (ssl.SSLError, CertificateError) as e: self.error(e) except socket.error, e: try: # socket.error can either return a string or a tuple if isinstance(e, tuple): (_errno, strerror) = e else: # Are we safe to hardcode the ETIMEDOUT error? (_errno, strerror) = (errno.ETIMEDOUT, str(e)) e = (_errno, strerror) # expected, do nothing if _errno == errno.EINPROGRESS: pass finally: self.error(e) def error(self, error): raw_error_str = str(error) if 'SSL23_GET_SERVER_HELLO' in str(error) or 'SSL3_GET_RECORD' in raw_error_str: error = T('This server does not allow SSL on this port') # Catch certificate errors if type(error) == CertificateError or 'CERTIFICATE_VERIFY_FAILED' in raw_error_str: # Log the raw message for debug purposes logging.info('Certificate error for host %s: %s', self.nw.server.host, raw_error_str) # Try to see if we should catch this message and provide better text if 'hostname' in raw_error_str: raw_error_str = T('Certificate hostname mismatch: the server hostname is not listed in the certificate. This is a server issue.') elif 'certificate verify failed' in raw_error_str: raw_error_str = T('Certificate not valid. This is most probably a server issue.') # Reformat error error = T('Server %s uses an untrusted certificate [%s]') % (self.nw.server.host, raw_error_str) error = '%s - %s: %s' % (error, T('Wiki'), 'https://sabnzbd.org/certificate-errors') # Prevent throwing a lot of errors or when testing server if error not in self.nw.server.warning and not self.blocking: logging.error(error) # Pass to server-test if self.blocking: raise CertificateError(error) # Blocking = server-test, pass directly to display code if self.blocking: raise socket.error(errno.ECONNREFUSED, str(error)) else: msg = "Failed to connect: %s" % (str(error)) msg = "%s %s@%s:%s" % (msg, self.nw.thrdnum, self.host, self.port) self.error_msg = msg logging.info(msg) self.nw.server.warning = msg class NewsWrapper(object): # Pre-define attributes to save memory __slots__ = ('server', 'thrdnum', 'blocking', 'timeout', 'article', 'data', 'lines', 'last_line', 'nntp', 'recv', 'connected', 'user_sent', 'pass_sent', 'group', 'user_ok', 'pass_ok', 'force_login') def __init__(self, server, thrdnum, block=False): self.server = server self.thrdnum = thrdnum self.blocking = block self.timeout = None self.article = None self.data = [] self.lines = [] self.last_line = '' self.nntp = None self.recv = None self.connected = False self.user_sent = False self.pass_sent = False self.group = None self.user_ok = False self.pass_ok = False self.force_login = False @property def status_code(self): """ Shorthand to get the code """ try: return self.data[0][:3] except: return '' def init_connect(self, write_fds): self.nntp = NNTP(self.server.hostip, self.server.port, self.server.info, self.server.ssl, self.server.send_group, self, self.server.username, self.server.password, self.blocking, write_fds) self.recv = self.nntp.sock.recv self.timeout = time.time() + self.server.timeout def finish_connect(self, code): if not (self.server.username or self.server.password or self.force_login): self.connected = True self.user_sent = True self.user_ok = True self.pass_sent = True self.pass_ok = True if code in ('501',) and self.user_sent: # Change to a sensible text code = '481' self.data[0] = T('Authentication failed, check username/password.') self.user_ok = True self.pass_sent = True if code == '480': self.force_login = True self.connected = False self.user_sent = False self.user_ok = False self.pass_sent = False self.pass_ok = False if code in ('400', '502'): raise NNTPPermanentError(nntp_to_msg(self.data)) elif not self.user_sent: command = 'authinfo user %s\r\n' % self.server.username self.nntp.sock.sendall(command) self.data = [] self.user_sent = True elif not self.user_ok: if code == '381': self.user_ok = True elif code == '281': # No login required self.user_ok = True self.pass_sent = True self.pass_ok = True self.connected = True if self.user_ok and not self.pass_sent: command = 'authinfo pass %s\r\n' % self.server.password self.nntp.sock.sendall(command) self.data = [] self.pass_sent = True elif self.user_ok and not self.pass_ok: if code != '281': # Assume that login failed (code 481 or other) raise NNTPPermanentError(nntp_to_msg(self.data)) else: self.connected = True self.timeout = time.time() + self.server.timeout def body(self, precheck): self.timeout = time.time() + self.server.timeout if precheck: if self.server.have_stat: command = 'STAT <%s>\r\n' % (self.article.article) else: command = 'HEAD <%s>\r\n' % (self.article.article) elif self.server.have_body: command = 'BODY <%s>\r\n' % (self.article.article) else: command = 'ARTICLE <%s>\r\n' % (self.article.article) self.nntp.sock.sendall(command) self.data = [] def send_group(self, group): self.timeout = time.time() + self.server.timeout command = 'GROUP %s\r\n' % (group) self.nntp.sock.sendall(command) self.data = [] def recv_chunk(self, block=False): """ Receive data, return #bytes, done, skip """ self.timeout = time.time() + self.server.timeout while 1: try: if self.nntp.nw.server.ssl: # SSL chunks come in 16K frames # Setting higher limits results in slowdown chunk = self.recv(16384) else: # Get as many bytes as possible chunk = self.recv(262144) break except WantReadError as e: # Workaround for Python <2.7.9 so we only catch WantReadError's if not sabnzbd.HAVE_SSL_CONTEXT and e.errno != 2: raise # SSL connections will block until they are ready. # Either ignore the connection until it responds # Or wait in a loop until it responds if block: # time.sleep(0.0001) continue else: return (0, False, True) # Data is processed differently depending on C-yEnc version if sabnzbd.decoder.SABYENC_ENABLED: # Append so we can do 1 join(), much faster than multiple! self.data.append(chunk) # Official end-of-article is ".\r\n" but sometimes it can get lost between 2 chunks chunk_len = len(chunk) if chunk[-5:] == '\r\n.\r\n': return (chunk_len, True, False) elif chunk_len < 5 and len(self.data) > 1: # We need to make sure the end is not split over 2 chunks # This is faster than join() combine_chunk = self.data[-2][-5:] + chunk if combine_chunk[-5:] == '\r\n.\r\n': return (chunk_len, True, False) # Still in middle of data, so continue! return (chunk_len, False, False) else: self.last_line += chunk new_lines = self.last_line.split('\r\n') # See if incorrect newline-only was used # Do this as a special case to prevent using extra memory # for normal articles if len(new_lines) == 1 and '\r' not in self.last_line: new_lines = self.last_line.split('\n') self.last_line = new_lines.pop() # Already remove the starting dots for i in xrange(len(new_lines)): if new_lines[i][:2] == '..': new_lines[i] = new_lines[i][1:] self.lines.extend(new_lines) # For status-code purposes if not self.data: self.data.append(chunk) if self.lines and self.lines[-1] == '.': self.lines = self.lines[1:-1] return (len(chunk), True, False) else: return (len(chunk), False, False) def soft_reset(self): self.timeout = None self.article = None self.clear_data() def clear_data(self): self.data = [] self.lines = [] self.last_line = '' def hard_reset(self, wait=True, quit=True): if self.nntp: try: if quit: self.nntp.sock.sendall('QUIT\r\n') time.sleep(0.1) self.nntp.sock.close() except: pass self.__init__(self.server, self.thrdnum) # Wait before re-using this newswrapper if wait: # Reset due to error condition, use server timeout self.timeout = time.time() + self.server.timeout else: # Reset for internal reasons, just wait 5 sec self.timeout = time.time() + 5 def terminate(self, quit=False): """ Close connection and remove nntp object """ if self.nntp: try: if quit: self.nntp.sock.sendall('QUIT\r\n') time.sleep(0.1) self.nntp.sock.close() except: pass del self.nntp SABnzbd-2.3.2/sabnzbd/notifier.py0000644000000000000000000004621313217005257014753 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # """ sabnzbd.notifier - Send notifications to any notification services """ from __future__ import with_statement import os.path import logging import socket import urllib2 import httplib import urllib import subprocess import json from threading import Thread import sabnzbd import sabnzbd.cfg from sabnzbd.encoding import unicoder from sabnzbd.constants import NOTIFY_KEYS from sabnzbd.misc import split_host, make_script_path from sabnzbd.newsunpack import external_script from gntp.core import GNTPRegister from gntp.notifier import GrowlNotifier import gntp.errors try: import Growl # Detect classic Growl (older than 1.3) _HAVE_CLASSIC_GROWL = os.path.isfile('/Library/PreferencePanes/Growl.prefPane/Contents/MacOS/Growl') except ImportError: _HAVE_CLASSIC_GROWL = False try: import warnings # Make any warnings exceptions, so that pynotify is ignored # PyNotify will not work with Python 2.5 (due to next three lines) with warnings.catch_warnings(): warnings.simplefilter("error") import pynotify _HAVE_NTFOSD = True # Check for working version, not all pynotify are the same if not hasattr(pynotify, 'init'): _HAVE_NTFOSD = False except: _HAVE_NTFOSD = False ############################################################################## # Define translatable message table ############################################################################## TT = lambda x: x NOTIFICATION = { 'startup': TT('Startup/Shutdown'), #: Notification 'download': TT('Added NZB'), #: Notification 'pp': TT('Post-processing started'), # : Notification 'complete': TT('Job finished'), #: Notification 'failed': TT('Job failed'), #: Notification 'warning': TT('Warning'), #: Notification 'error': TT('Error'), #: Notification 'disk_full': TT('Disk full'), #: Notification 'queue_done': TT('Queue finished'), #: Notification 'new_login': TT('User logged in'), #: Notification 'other': TT('Other Messages') #: Notification } ############################################################################## # Setup platform dependent Growl support ############################################################################## _GROWL = None # Instance of the Notifier after registration _GROWL_REG = False # Succesful registration _GROWL_DATA = (None, None) # Address and password def get_icon(): icon = os.path.join(os.path.join(sabnzbd.DIR_PROG, 'icons'), 'sabnzbd.ico') if not os.path.isfile(icon): icon = os.path.join(sabnzbd.DIR_PROG, 'sabnzbd.ico') if os.path.isfile(icon): fp = open(icon, 'rb') icon = fp.read() fp.close() else: icon = None return icon def change_value(): """ Signal that we should register with a new Growl server """ global _GROWL_REG _GROWL_REG = False def have_ntfosd(): """ Return if any PyNotify support is present """ return bool(_HAVE_NTFOSD) def check_classes(gtype, section): """ Check if `gtype` is enabled in `section` """ try: return sabnzbd.config.get_config(section, '%s_prio_%s' % (section, gtype))() > 0 except TypeError: logging.debug('Incorrect Notify option %s:%s_prio_%s', section, section, gtype) return False def get_prio(gtype, section): """ Check prio of `gtype` in `section` """ try: return sabnzbd.config.get_config(section, '%s_prio_%s' % (section, gtype))() except TypeError: logging.debug('Incorrect Notify option %s:%s_prio_%s', section, section, gtype) return -1000 def check_cat(section, job_cat, keyword=None): """ Check if `job_cat` is enabled in `section`. * = All, if no other categories selected. """ if not job_cat: return True try: if not keyword: keyword = section section_cats = sabnzbd.config.get_config(section, '%s_cats' % keyword)() return (['*'] == section_cats or job_cat in section_cats) except TypeError: logging.debug('Incorrect Notify option %s:%s_cats', section, section) return True def send_notification(title, msg, gtype, job_cat=None): """ Send Notification message """ # Notification Center if sabnzbd.DARWIN and sabnzbd.cfg.ncenter_enable(): if check_classes(gtype, 'ncenter') and check_cat('ncenter', job_cat): send_notification_center(title, msg, gtype) # Windows if sabnzbd.WIN32 and sabnzbd.cfg.acenter_enable(): if check_classes(gtype, 'acenter') and check_cat('acenter', job_cat): send_windows(title, msg, gtype) # Growl if sabnzbd.cfg.growl_enable() and check_classes(gtype, 'growl') and check_cat('growl', job_cat): if _HAVE_CLASSIC_GROWL and not sabnzbd.cfg.growl_server(): return send_local_growl(title, msg, gtype) else: Thread(target=send_growl, args=(title, msg, gtype)).start() # Prowl if sabnzbd.cfg.prowl_enable() and check_cat('prowl', job_cat): if sabnzbd.cfg.prowl_apikey(): Thread(target=send_prowl, args=(title, msg, gtype)).start() # Pushover if sabnzbd.cfg.pushover_enable() and check_cat('pushover', job_cat): if sabnzbd.cfg.pushover_token(): Thread(target=send_pushover, args=(title, msg, gtype)).start() # Pushbullet if sabnzbd.cfg.pushbullet_enable() and check_cat('pushbullet', job_cat): if sabnzbd.cfg.pushbullet_apikey() and check_classes(gtype, 'pushbullet'): Thread(target=send_pushbullet, args=(title, msg, gtype)).start() # Notification script. if sabnzbd.cfg.nscript_enable() and check_cat('nscript', job_cat): if sabnzbd.cfg.nscript_script(): Thread(target=send_nscript, args=(title, msg, gtype)).start() # NTFOSD if have_ntfosd() and sabnzbd.cfg.ntfosd_enable(): if check_classes(gtype, 'ntfosd') and check_cat('ntfosd', job_cat): send_notify_osd(title, msg) def reset_growl(): """ Reset Growl (after changing language) """ global _GROWL, _GROWL_REG _GROWL = None _GROWL_REG = False def register_growl(growl_server, growl_password): """ Register this app with Growl """ error = None host, port = split_host(growl_server or '') sys_name = hostname(host) # Reduce logging of Growl in Debug/Info mode logging.getLogger('gntp').setLevel(logging.WARNING) # Clean up persistent data in GNTP to make re-registration work GNTPRegister.notifications = [] GNTPRegister.headers = {} growler = GrowlNotifier( applicationName='SABnzbd%s' % sys_name, applicationIcon=get_icon(), notifications=[Tx(NOTIFICATION[key]) for key in NOTIFY_KEYS], hostname=host or 'localhost', port=port or 23053, password=growl_password or None ) try: ret = growler.register() if ret is None or isinstance(ret, bool): logging.info('Registered with Growl') ret = growler else: error = 'Cannot register with Growl %s' % str(ret) logging.debug(error) del growler ret = None except (gntp.errors.NetworkError, gntp.errors.AuthError) as err: error = 'Cannot register with Growl %s' % str(err) logging.debug(error) del growler ret = None except: error = 'Unknown Growl registration error' logging.debug(error) logging.info("Traceback: ", exc_info=True) del growler ret = None return ret, error def send_growl(title, msg, gtype, test=None): """ Send Growl message """ global _GROWL, _GROWL_REG, _GROWL_DATA # support testing values from UI if test: growl_server = test.get('growl_server') or None growl_password = test.get('growl_password') or None else: growl_server = sabnzbd.cfg.growl_server() growl_password = sabnzbd.cfg.growl_password() for n in (0, 1): if not _GROWL_REG: _GROWL = None if (growl_server, growl_password) != _GROWL_DATA: reset_growl() if not _GROWL: _GROWL, error = register_growl(growl_server, growl_password) if _GROWL: _GROWL_REG = True if isinstance(msg, unicode): msg = msg.decode('utf-8') elif not isinstance(msg, str): msg = str(msg) logging.debug('Send to Growl: %s %s %s', gtype, title, msg) try: ret = _GROWL.notify( noteType=Tx(NOTIFICATION.get(gtype, 'other')), title=title, description=unicoder(msg), ) if ret is None or isinstance(ret, bool): return None elif ret[0] == '401': _GROWL = False else: logging.debug('Growl error %s', ret) return 'Growl error %s', ret except (gntp.errors.NetworkError, gntp.errors.AuthError) as err: error = 'Growl error %s' % err logging.debug(error) return error except: error = 'Growl error (unknown)' logging.debug(error) return error else: return error return None ############################################################################## # Local OSX Growl support ############################################################################## if _HAVE_CLASSIC_GROWL: _local_growl = None if os.path.isfile('sabnzbdplus.icns'): _OSX_ICON = Growl.Image.imageFromPath('sabnzbdplus.icns') elif os.path.isfile('osx/resources/sabnzbdplus.icns'): _OSX_ICON = Growl.Image.imageFromPath('osx/resources/sabnzbdplus.icns') else: _OSX_ICON = Growl.Image.imageWithIconForApplication('Terminal') def send_local_growl(title, msg, gtype): """ Send to local Growl server, OSX-only """ global _local_growl if not _local_growl: notes = [Tx(NOTIFICATION[key]) for key in NOTIFY_KEYS] _local_growl = Growl.GrowlNotifier( applicationName='SABnzbd', applicationIcon=_OSX_ICON, notifications=notes, defaultNotifications=notes ) _local_growl.register() _local_growl.notify(Tx(NOTIFICATION.get(gtype, 'other')), title, msg) return None ############################################################################## # Ubuntu NotifyOSD Support ############################################################################## _NTFOSD = False def send_notify_osd(title, message): """ Send a message to NotifyOSD """ global _NTFOSD if not _HAVE_NTFOSD: return T('Not available') # : Function is not available on this OS error = 'NotifyOSD not working' icon = os.path.join(sabnzbd.DIR_PROG, 'sabnzbd.ico') _NTFOSD = _NTFOSD or pynotify.init('icon-summary-body') if _NTFOSD: logging.info('Send to NotifyOSD: %s / %s', title, message) try: note = pynotify.Notification(title, message, icon) note.show() except: # Apparently not implemented on this system logging.info(error) return error return None else: return error def ncenter_path(): """ Return path of Notification Center tool, if it exists """ tool = os.path.normpath(os.path.join(sabnzbd.DIR_PROG, '../Resources/SABnzbd.app/Contents/MacOS/SABnzbd')) if os.path.exists(tool): return tool else: return None def send_notification_center(title, msg, gtype): """ Send message to Mountain Lion's Notification Center """ tool = ncenter_path() if tool: try: command = [tool, '-title', title, '-message', msg, '-group', Tx(NOTIFICATION.get(gtype, 'other'))] proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False) output = proc.stdout.read() proc.wait() if 'Notification delivered' in output or 'Removing previously' in output: output = '' except: logging.info('Cannot run notifier "%s"', tool) logging.debug("Traceback: ", exc_info=True) output = 'Notifier tool crashed' else: output = 'Notifier app not found' return output.strip('*\n ') def hostname(host=True): """ Return host's pretty name """ if sabnzbd.WIN32: sys_name = os.environ.get('computername', 'unknown') else: try: sys_name = os.uname()[1] except: sys_name = 'unknown' if host: return '@%s' % sys_name.lower() else: return '' def send_prowl(title, msg, gtype, force=False, test=None): """ Send message to Prowl """ if test: apikey = test.get('prowl_apikey') else: apikey = sabnzbd.cfg.prowl_apikey() if not apikey: return T('Cannot send, missing required data') title = Tx(NOTIFICATION.get(gtype, 'other')) title = urllib2.quote(title.encode('utf8')) msg = urllib2.quote(msg.encode('utf8')) prio = get_prio(gtype, 'prowl') if force: prio = 0 if prio > -3: url = 'https://api.prowlapp.com/publicapi/add?apikey=%s&application=SABnzbd' \ '&event=%s&description=%s&priority=%d' % (apikey, title, msg, prio) try: urllib2.urlopen(url) return '' except: logging.warning(T('Failed to send Prowl message')) logging.info("Traceback: ", exc_info=True) return T('Failed to send Prowl message') return '' def send_pushover(title, msg, gtype, force=False, test=None): """ Send message to pushover """ if test: apikey = test.get('pushover_token') userkey = test.get('pushover_userkey') device = test.get('pushover_device') else: apikey = sabnzbd.cfg.pushover_token() userkey = sabnzbd.cfg.pushover_userkey() device = sabnzbd.cfg.pushover_device() emergency_retry = sabnzbd.cfg.pushover_emergency_retry() emergency_expire = sabnzbd.cfg.pushover_emergency_expire() if not apikey or not userkey: return T('Cannot send, missing required data') title = Tx(NOTIFICATION.get(gtype, 'other')) prio = get_prio(gtype, 'pushover') if force: prio = 1 if prio == 2: body = { "token": apikey, "user": userkey, "device": device, "title": title, "message": msg, "priority": prio, "retry": emergency_retry, "expire": emergency_expire } return do_send_pushover(body) if prio > -3 and prio < 2: body = { "token": apikey, "user": userkey, "device": device, "title": title, "message": msg, "priority": prio, } return do_send_pushover(body) def do_send_pushover(body): try: conn = httplib.HTTPSConnection("api.pushover.net:443") conn.request("POST", "/1/messages.json", urllib.urlencode(body), {"Content-type": "application/x-www-form-urlencoded"}) res = conn.getresponse() if res.status != 200: logging.error(T('Bad response from Pushover (%s): %s'), res.status, res.read()) return T('Failed to send pushover message') else: return '' except: logging.warning(T('Failed to send pushover message')) logging.info("Traceback: ", exc_info=True) return T('Failed to send pushover message') def send_pushbullet(title, msg, gtype, force=False, test=None): """ Send message to Pushbullet """ if test: apikey = test.get('pushbullet_apikey') device = test.get('pushbullet_device') else: apikey = sabnzbd.cfg.pushbullet_apikey() device = sabnzbd.cfg.pushbullet_device() if not apikey: return T('Cannot send, missing required data') title = u'SABnzbd: ' + Tx(NOTIFICATION.get(gtype, 'other')) try: conn = httplib.HTTPSConnection('api.pushbullet.com:443') conn.request('POST', '/v2/pushes', json.dumps({ 'type': 'note', 'device': device, 'title': title, 'body': msg}), headers={'Authorization': 'Bearer ' + apikey, 'Content-type': 'application/json'}) res = conn.getresponse() if res.status != 200: logging.error(T('Bad response from Pushbullet (%s): %s'), res.status, res.read()) else: logging.info('Successfully sent to Pushbullet') except: logging.warning(T('Failed to send pushbullet message')) logging.info('Traceback: ', exc_info=True) return T('Failed to send pushbullet message') return '' def send_nscript(title, msg, gtype, force=False, test=None): """ Run user's notification script """ if test: script = test.get('nscript_script') parameters = test.get('nscript_parameters') else: script = sabnzbd.cfg.nscript_script() parameters = sabnzbd.cfg.nscript_parameters() if not script: return T('Cannot send, missing required data') title = u'SABnzbd: ' + Tx(NOTIFICATION.get(gtype, 'other')) if force or check_classes(gtype, 'nscript'): script_path = make_script_path(script) if script_path: output, ret = external_script(script_path, gtype, title, msg, parameters) if ret: logging.error(T('Script returned exit code %s and output "%s"') % (ret, output)) return T('Script returned exit code %s and output "%s"') % (ret, output) else: logging.info('Successfully executed notification script ' + script_path) else: return T('Notification script "%s" does not exist') % script_path return '' def send_windows(title, msg, gtype): if sabnzbd.WINTRAY and not sabnzbd.WINTRAY.terminate: try: sabnzbd.WINTRAY.sendnotification(title, msg) except: logging.info(T('Failed to send Windows notification')) logging.debug("Traceback: ", exc_info=True) return T('Failed to send Windows notification') return None SABnzbd-2.3.2/sabnzbd/nzbqueue.py0000644000000000000000000011502713217005257014772 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.nzbqueue - nzb queue """ import os import logging import time import datetime import sabnzbd from sabnzbd.nzbstuff import NzbObject from sabnzbd.misc import exit_sab, cat_to_opts, remove_file, \ get_admin_path, remove_all, globber_full, int_conv, caller_name from sabnzbd.panic import panic_queue import sabnzbd.database as database from sabnzbd.decorators import NzbQueueLocker from sabnzbd.constants import QUEUE_FILE_NAME, QUEUE_VERSION, FUTURE_Q_FOLDER, \ JOB_ADMIN, LOW_PRIORITY, NORMAL_PRIORITY, HIGH_PRIORITY, TOP_PRIORITY, \ REPAIR_PRIORITY, STOP_PRIORITY, VERIFIED_FILE, \ Status, IGNORED_FOLDERS, QNFO import sabnzbd.cfg as cfg from sabnzbd.articlecache import ArticleCache import sabnzbd.downloader from sabnzbd.assembler import Assembler, file_has_articles import sabnzbd.notifier as notifier from sabnzbd.encoding import platform_encode from sabnzbd.bpsmeter import BPSMeter from sabnzbd.dirscanner import ProcessSingleFile class NzbQueue(object): """ Singleton NzbQueue """ do = None def __init__(self): self.__top_only = cfg.top_only() self.__nzo_list = [] self.__nzo_table = {} NzbQueue.do = self def read_queue(self, repair): """ Read queue from disk, supporting repair modes 0 = no repairs 1 = use existing queue, add missing "incomplete" folders 2 = Discard all queue admin, reconstruct from "incomplete" folders """ nzo_ids = [] if repair < 2: # Read the queue from the saved files data = sabnzbd.load_admin(QUEUE_FILE_NAME) # Process the data and check compatibility nzo_ids = self.check_compatibility(data) # First handle jobs in the queue file folders = [] for nzo_id in nzo_ids: folder, _id = os.path.split(nzo_id) path = get_admin_path(folder, future=False) # Try as normal job nzo = sabnzbd.load_data(_id, path, remove=False) if not nzo: # Try as future job path = get_admin_path(folder, future=True) nzo = sabnzbd.load_data(_id, path) if nzo: self.add(nzo, save=False, quiet=True) folders.append(folder) # Scan for any folders in "incomplete" that are not yet in the queue if repair: self.scan_jobs(not folders) # Handle any lost future jobs for item in globber_full(os.path.join(cfg.admin_dir.get_path(), FUTURE_Q_FOLDER)): path, nzo_id = os.path.split(item) if nzo_id not in self.__nzo_table: if nzo_id.startswith('SABnzbd_nzo'): nzo = sabnzbd.load_data(nzo_id, path, remove=True) if nzo: self.add(nzo, save=True) else: try: remove_file(item) except: pass def check_compatibility(self, data): """ Do compatibility checks on the loaded data """ nzo_ids = [] if not data: # Warn about old queue if sabnzbd.OLD_QUEUE and cfg.warned_old_queue() < QUEUE_VERSION: logging.warning(T('Old queue detected, use Status->Repair to convert the queue')) cfg.warned_old_queue.set(QUEUE_VERSION) sabnzbd.config.save_config() else: # Try to process try: queue_vers, nzo_ids, dummy = data if not queue_vers == QUEUE_VERSION: nzo_ids = [] logging.error(T('Incompatible queuefile found, cannot proceed')) if not repair: panic_queue(os.path.join(cfg.admin_dir.get_path(), QUEUE_FILE_NAME)) exit_sab(2) except ValueError: nzo_ids = [] logging.error(T('Error loading %s, corrupt file detected'), os.path.join(cfg.admin_dir.get_path(), QUEUE_FILE_NAME)) # We need to do a repair in case of old-style pickles if not cfg.converted_nzo_pickles(): for nzo_id in nzo_ids: folder, _id = os.path.split(nzo_id) path = get_admin_path(folder, future=False) # This will update them but preserve queue-order if os.path.exists(os.path.join(path, _id)): self.repair_job(os.path.dirname(path)) continue # Remove any future-jobs, we can't save those for item in globber_full(os.path.join(cfg.admin_dir.get_path(), FUTURE_Q_FOLDER)): remove_file(item) # Done converting cfg.converted_nzo_pickles.set(True) sabnzbd.config.save_config() nzo_ids = [] return nzo_ids @NzbQueueLocker def scan_jobs(self, all=False, action=True): """ Scan "incomplete" for missing folders, 'all' is True: Include active folders 'action' is True, do the recovery action returns list of orphaned folders """ result = [] # Folders from the download queue if all: registered = [] else: registered = [nzo.work_name for nzo in self.__nzo_list] # Retryable folders from History items = sabnzbd.api.build_history(output=True)[0] # Anything waiting or active or retryable is a known item registered.extend([platform_encode(os.path.basename(item['path'])) for item in items if item['retry'] or item['loaded'] or item['status'] == Status.QUEUED]) # Repair unregistered folders for folder in globber_full(cfg.download_dir.get_path()): name = os.path.basename(folder) if os.path.isdir(folder) and name not in registered and name not in IGNORED_FOLDERS: if action: logging.info('Repairing job %s', folder) self.repair_job(folder) result.append(os.path.basename(folder)) else: if action: logging.info('Skipping repair for job %s', folder) return result def retry_all_jobs(self, history_db): """ Retry all retryable jobs in History """ result = [] # Retryable folders from History items = sabnzbd.api.build_history()[0] registered = [(platform_encode(os.path.basename(item['path'])), item['nzo_id']) for item in items if item['retry']] for job in registered: logging.info('Repairing job %s', job[0]) result.append(self.repair_job(job[0])) history_db.remove_history(job[1]) return bool(result) def repair_job(self, folder, new_nzb=None, password=None): """ Reconstruct admin for a single job folder, optionally with new NZB """ def all_verified(path): """ Return True when all sets have been successfully verified """ verified = sabnzbd.load_data(VERIFIED_FILE, path, remove=False) or {'x': False} return all(verified[x] for x in verified) nzo_id = None name = os.path.basename(folder) path = os.path.join(folder, JOB_ADMIN) if hasattr(new_nzb, 'filename'): filename = new_nzb.filename else: filename = '' if not filename: if not all_verified(path): filename = globber_full(path, '*.gz') if len(filename) > 0: logging.debug('Repair job %s by reparsing stored NZB', name) nzo_id = sabnzbd.add_nzbfile(filename[0], pp=None, script=None, cat=None, priority=None, nzbname=name, reuse=True, password=password)[1] else: logging.debug('Repair job %s without stored NZB', name) nzo = NzbObject(name, pp=None, script=None, nzb='', cat=None, priority=None, nzbname=name, reuse=True) nzo.password = password self.add(nzo) nzo_id = nzo.nzo_id else: remove_all(path, '*.gz') logging.debug('Repair job %s with new NZB (%s)', name, filename) nzo_id = sabnzbd.add_nzbfile(new_nzb, pp=None, script=None, cat=None, priority=None, nzbname=name, reuse=True, password=password)[1] return nzo_id def send_back(self, nzo): """ Send back job to queue after successful pre-check """ try: nzb_path = globber_full(nzo.workpath, '*.gz')[0] except: logging.debug('Failed to find NZB file after pre-check (%s)', nzo.nzo_id) return res, nzo_ids = ProcessSingleFile(nzo.work_name + '.nzb', nzb_path, keep=True, reuse=True) if res == 0 and nzo_ids: nzo = self.replace_in_q(nzo, nzo_ids[0]) # Reset reuse flag to make pause/abort on encryption possible nzo.reuse = False @NzbQueueLocker def replace_in_q(self, nzo, nzo_id): """ Replace nzo by new in at the same spot in the queue, destroy nzo """ # Must be a separate function from "send_back()", due to the required queue-lock try: old_id = nzo.nzo_id new_nzo = self.get_nzo(nzo_id) pos = self.__nzo_list.index(new_nzo) targetpos = self.__nzo_list.index(nzo) self.__nzo_list[targetpos] = new_nzo self.__nzo_list.pop(pos) # Reuse the old nzo_id new_nzo.nzo_id = old_id # Therefore: remove the new nzo_id del self.__nzo_table[nzo_id] # And attach the new nzo to the old nzo_id self.__nzo_table[old_id] = new_nzo logging.info('Replacing in queue %s by %s', nzo.final_name, new_nzo.final_name) del nzo return new_nzo except: logging.error(T('Failed to restart NZB after pre-check (%s)'), nzo.nzo_id) logging.info("Traceback: ", exc_info=True) return nzo @NzbQueueLocker def save(self, save_nzo=None): """ Save queue, all nzo's or just the specified one """ logging.info("Saving queue") nzo_ids = [] # Aggregate nzo_ids and save each nzo for nzo in self.__nzo_list[:]: if not nzo.is_gone(): nzo_ids.append(os.path.join(nzo.work_name, nzo.nzo_id)) if save_nzo is None or nzo is save_nzo: if not nzo.futuretype: # Also includes save_data for NZO nzo.save_to_disk() else: sabnzbd.save_data(nzo, nzo.nzo_id, nzo.workpath) sabnzbd.save_admin((QUEUE_VERSION, nzo_ids, []), QUEUE_FILE_NAME) def set_top_only(self, value): self.__top_only = value def generate_future(self, msg, pp=None, script=None, cat=None, url=None, priority=NORMAL_PRIORITY, nzbname=None): """ Create and return a placeholder nzo object """ logging.debug('Creating placeholder NZO') future_nzo = NzbObject(msg, pp, script, None, True, cat=cat, url=url, priority=priority, nzbname=nzbname, status=Status.GRABBING) self.add(future_nzo) return future_nzo def change_opts(self, nzo_ids, pp): result = 0 for nzo_id in [item.strip() for item in nzo_ids.split(',')]: if nzo_id in self.__nzo_table: self.__nzo_table[nzo_id].set_pp(pp) result += 1 return result def change_script(self, nzo_ids, script): result = 0 for nzo_id in [item.strip() for item in nzo_ids.split(',')]: if nzo_id in self.__nzo_table: self.__nzo_table[nzo_id].script = script logging.info('Set script=%s for job %s', script, self.__nzo_table[nzo_id].final_name) result += 1 return result def change_cat(self, nzo_ids, cat, explicit_priority=None): result = 0 for nzo_id in [item.strip() for item in nzo_ids.split(',')]: if nzo_id in self.__nzo_table: nzo = self.__nzo_table[nzo_id] nzo.cat, pp, nzo.script, prio = cat_to_opts(cat) logging.info('Set cat=%s for job %s', cat, nzo.final_name) nzo.set_pp(pp) if explicit_priority is None: self.set_priority(nzo_id, prio) # Abort any ongoing unpacking if the category changed nzo.abort_direct_unpacker() result += 1 return result def change_name(self, nzo_id, name, password=None): if nzo_id in self.__nzo_table: nzo = self.__nzo_table[nzo_id] logging.info('Renaming %s to %s', nzo.final_name, name) # Abort any ongoing unpacking if the name changed (dirs change) nzo.abort_direct_unpacker() if not nzo.futuretype: nzo.set_final_name_pw(name, password) else: # Reset url fetch wait time nzo.url_wait = None nzo.url_tries = 0 return True else: return False def get_nzo(self, nzo_id): if nzo_id in self.__nzo_table: return self.__nzo_table[nzo_id] else: return None @NzbQueueLocker def add(self, nzo, save=True, quiet=False): if not nzo.nzo_id: nzo.nzo_id = sabnzbd.get_new_id('nzo', nzo.workpath, self.__nzo_table) # If no files are to be downloaded anymore, send to postproc if not nzo.files and not nzo.futuretype: self.end_job(nzo) return '' # Reset try_lists nzo.reset_try_list() if nzo.nzo_id: nzo.deleted = False priority = nzo.priority if sabnzbd.scheduler.analyse(False, priority): nzo.status = Status.PAUSED self.__nzo_table[nzo.nzo_id] = nzo if priority > HIGH_PRIORITY: # Top and repair priority items are added to the top of the queue self.__nzo_list.insert(0, nzo) elif priority == LOW_PRIORITY: self.__nzo_list.append(nzo) else: # for high priority we need to add the item at the bottom # of any other high priority items above the normal priority # for normal priority we need to add the item at the bottom # of the normal priority items above the low priority if self.__nzo_list: pos = 0 added = False for position in self.__nzo_list: if position.priority < priority: self.__nzo_list.insert(pos, nzo) added = True break pos += 1 if not added: # if there are no other items classed as a lower priority # then it will be added to the bottom of the queue self.__nzo_list.append(nzo) else: # if the queue is empty then simple append the item to the bottom self.__nzo_list.append(nzo) if save: self.save(nzo) if not (quiet or nzo.status in ('Fetching',)): notifier.send_notification(T('NZB added to queue'), nzo.filename, 'download', nzo.cat) if not quiet and cfg.auto_sort(): self.sort_by_avg_age() return nzo.nzo_id @NzbQueueLocker def remove(self, nzo_id, add_to_history=True, save=True, cleanup=True, keep_basic=False, del_files=False): if nzo_id in self.__nzo_table: nzo = self.__nzo_table.pop(nzo_id) nzo.deleted = True if cleanup and not nzo.is_gone(): nzo.status = Status.DELETED self.__nzo_list.remove(nzo) if add_to_history: # Create the history DB instance history_db = database.HistoryDB() # Add the nzo to the database. Only the path, script and time taken is passed # Other information is obtained from the nzo history_db.add_history_db(nzo, '', '', 0, '', '') history_db.close() sabnzbd.history_updated() elif cleanup: self.cleanup_nzo(nzo, keep_basic, del_files) sabnzbd.remove_data(nzo_id, nzo.workpath) logging.info('[%s] Removed job %s', caller_name(), nzo.final_name) if save: self.save(nzo) else: nzo_id = None return nzo_id def remove_multiple(self, nzo_ids, del_files=False): removed = [] for nzo_id in nzo_ids: if self.remove(nzo_id, add_to_history=False, save=False, keep_basic=not del_files, del_files=del_files): removed.append(nzo_id) # Save with invalid nzo_id, to that only queue file is saved self.save('x') # Any files left? Otherwise let's disconnect if self.actives(grabs=False) == 0 and cfg.autodisconnect(): # This was the last job, close server connections sabnzbd.downloader.Downloader.do.disconnect() return removed @NzbQueueLocker def remove_all(self, search=None): if search: search = search.lower() removed = [] for nzo_id in self.__nzo_table.keys(): if (not search) or search in self.__nzo_table[nzo_id].final_name_pw_clean.lower(): nzo = self.__nzo_table.pop(nzo_id) nzo.deleted = True self.__nzo_list.remove(nzo) sabnzbd.remove_data(nzo_id, nzo.workpath) self.cleanup_nzo(nzo) removed.append(nzo_id) self.save() return removed def remove_nzf(self, nzo_id, nzf_id, force_delete=False): removed = [] if nzo_id in self.__nzo_table: nzo = self.__nzo_table[nzo_id] nzf = nzo.get_nzf_by_id(nzf_id) if nzf: removed.append(nzf_id) nzo.abort_direct_unpacker() post_done = nzo.remove_nzf(nzf) if post_done: if nzo.finished_files: self.end_job(nzo) else: self.remove(nzo_id, add_to_history=False, keep_basic=False) elif force_delete: # Force-remove all trace nzo.bytes -= nzf.bytes nzo.bytes_tried -= (nzf.bytes - nzf.bytes_left) del nzo.files_table[nzf_id] nzo.finished_files.remove(nzf) logging.info('Removed NZFs %s from job %s', removed, nzo.final_name) return removed def pause_multiple_nzo(self, nzo_ids): handled = [] for nzo_id in nzo_ids: self.pause_nzo(nzo_id) handled.append(nzo_id) return handled def pause_nzo(self, nzo_id): handled = [] if nzo_id in self.__nzo_table: nzo = self.__nzo_table[nzo_id] nzo.pause() logging.info("Paused nzo: %s", nzo_id) handled.append(nzo_id) return handled def resume_multiple_nzo(self, nzo_ids): handled = [] for nzo_id in nzo_ids: self.resume_nzo(nzo_id) handled.append(nzo_id) return handled @NzbQueueLocker def resume_nzo(self, nzo_id): handled = [] if nzo_id in self.__nzo_table: nzo = self.__nzo_table[nzo_id] nzo.resume() nzo.reset_all_try_lists() logging.info("Resumed nzo: %s", nzo_id) handled.append(nzo_id) return handled @NzbQueueLocker def switch(self, item_id_1, item_id_2): try: # Allow an index as second parameter, easier for some skins i = int(item_id_2) item_id_2 = self.__nzo_list[i].nzo_id except: pass try: nzo1 = self.__nzo_table[item_id_1] nzo2 = self.__nzo_table[item_id_2] except KeyError: # One or both jobs missing return (-1, 0) if nzo1 == nzo2: return (-1, 0) # get the priorities of the two items nzo1_priority = nzo1.priority nzo2_priority = nzo2.priority try: # get the item id of the item below to use in priority changing item_id_3 = self.__nzo_list[i + 1].nzo_id # if there is an item below the id1 and id2 then we need that too # to determine whether to change the priority nzo3 = self.__nzo_table[item_id_3] nzo3_priority = nzo3.priority # if id1 is surrounded by items of a different priority then change it's pririty to match if nzo2_priority != nzo1_priority and nzo3_priority != nzo1_priority or nzo2_priority > nzo1_priority: nzo1.priority = nzo2_priority except: nzo1.priority = nzo2_priority item_id_pos1 = -1 item_id_pos2 = -1 for i in xrange(len(self.__nzo_list)): if item_id_1 == self.__nzo_list[i].nzo_id: item_id_pos1 = i elif item_id_2 == self.__nzo_list[i].nzo_id: item_id_pos2 = i if (item_id_pos1 > -1) and (item_id_pos2 > -1): item = self.__nzo_list[item_id_pos1] logging.info('Switching job [%s] %s => [%s] %s', item_id_pos1, item.final_name, item_id_pos2, self.__nzo_list[item_id_pos2].final_name) del self.__nzo_list[item_id_pos1] self.__nzo_list.insert(item_id_pos2, item) return (item_id_pos2, nzo1.priority) # If moving failed/no movement took place return (-1, nzo1.priority) @NzbQueueLocker def move_up_bulk(self, nzo_id, nzf_ids, size): if nzo_id in self.__nzo_table: for unused in range(size): self.__nzo_table[nzo_id].move_up_bulk(nzf_ids) @NzbQueueLocker def move_top_bulk(self, nzo_id, nzf_ids): if nzo_id in self.__nzo_table: self.__nzo_table[nzo_id].move_top_bulk(nzf_ids) @NzbQueueLocker def move_down_bulk(self, nzo_id, nzf_ids, size): if nzo_id in self.__nzo_table: for unused in range(size): self.__nzo_table[nzo_id].move_down_bulk(nzf_ids) @NzbQueueLocker def move_bottom_bulk(self, nzo_id, nzf_ids): if nzo_id in self.__nzo_table: self.__nzo_table[nzo_id].move_bottom_bulk(nzf_ids) @NzbQueueLocker def sort_by_avg_age(self, reverse=False): logging.info("Sorting by average date... (reversed:%s)", reverse) self.__nzo_list = sort_queue_function(self.__nzo_list, _nzo_date_cmp, reverse) @NzbQueueLocker def sort_by_name(self, reverse=False): logging.info("Sorting by name... (reversed:%s)", reverse) self.__nzo_list = sort_queue_function(self.__nzo_list, _nzo_name_cmp, reverse) @NzbQueueLocker def sort_by_size(self, reverse=False): logging.info("Sorting by size... (reversed:%s)", reverse) self.__nzo_list = sort_queue_function(self.__nzo_list, _nzo_size_cmp, reverse) def sort_queue(self, field, reverse=None): if isinstance(reverse, basestring): if reverse.lower() == 'desc': reverse = True else: reverse = False if reverse is None: reverse = False if field.lower() == 'name': self.sort_by_name(reverse) elif field.lower() == 'size' or field.lower() == 'bytes': self.sort_by_size(reverse) elif field.lower() == 'avg_age': self.sort_by_avg_age(reverse) else: logging.debug("Sort: %s not recognized", field) @NzbQueueLocker def __set_priority(self, nzo_id, priority): """ Sets the priority on the nzo and places it in the queue at the appropriate position """ try: priority = int_conv(priority) nzo = self.__nzo_table[nzo_id] nzo_id_pos1 = -1 pos = -1 # If priority == STOP_PRIORITY, then send to queue if priority == STOP_PRIORITY: self.end_job(nzo) return # Get the current position in the queue for i in xrange(len(self.__nzo_list)): if nzo_id == self.__nzo_list[i].nzo_id: nzo_id_pos1 = i break # Don't change priority and order if priority is the same as asked if priority == self.__nzo_list[nzo_id_pos1].priority: return nzo_id_pos1 nzo.set_priority(priority) if sabnzbd.scheduler.analyse(False, priority) and \ nzo.status in (Status.CHECKING, Status.DOWNLOADING, Status.QUEUED): nzo.status = Status.PAUSED elif nzo.status == Status.PAUSED: nzo.status = Status.QUEUED nzo.save_to_disk() if nzo_id_pos1 != -1: del self.__nzo_list[nzo_id_pos1] if priority == TOP_PRIORITY: # A top priority item (usually a completed download fetching pars) # is added to the top of the queue self.__nzo_list.insert(0, nzo) pos = 0 elif priority == LOW_PRIORITY: pos = len(self.__nzo_list) self.__nzo_list.append(nzo) else: # for high priority we need to add the item at the bottom # of any other high priority items above the normal priority # for normal priority we need to add the item at the bottom # of the normal priority items above the low priority if self.__nzo_list: p = 0 added = False for position in self.__nzo_list: if position.priority < priority: self.__nzo_list.insert(p, nzo) pos = p added = True break p += 1 if not added: # if there are no other items classed as a lower priority # then it will be added to the bottom of the queue pos = len(self.__nzo_list) self.__nzo_list.append(nzo) else: # if the queue is empty then simple append the item to the bottom self.__nzo_list.append(nzo) pos = 0 logging.info('Set priority=%s for job %s => position=%s ', priority, self.__nzo_table[nzo_id].final_name, pos) return pos except: return -1 @NzbQueueLocker def set_priority(self, nzo_ids, priority): try: n = -1 for nzo_id in [item.strip() for item in nzo_ids.split(',')]: n = self.__set_priority(nzo_id, priority) return n except: return -1 def reset_try_lists(self, article, article_reset=True): """ Let article get new fetcher and reset trylists """ article.fetcher = None if article_reset: article.reset_try_list() article.nzf.reset_try_list() article.nzf.nzo.reset_try_list() def reset_all_try_lists(self): for nzo in self.__nzo_list: nzo.reset_all_try_lists() def has_forced_items(self): """ Check if the queue contains any Forced Priority items to download while paused """ for nzo in self.__nzo_list: if nzo.priority == TOP_PRIORITY and nzo.status not in (Status.PAUSED, Status.GRABBING): return True return False def get_article(self, server, servers): """ Get next article for jobs in the queue Not locked for performance, since it only reads the queue """ for nzo in self.__nzo_list: # Not when queue paused and not a forced item if nzo.status not in (Status.PAUSED, Status.GRABBING) or nzo.priority == TOP_PRIORITY: # Check if past propagation delay, or forced if not cfg.propagation_delay() or nzo.priority == TOP_PRIORITY or (nzo.avg_stamp + float(cfg.propagation_delay() * 60)) < time.time(): if not nzo.server_in_try_list(server): article = nzo.get_article(server, servers) if article: return article # Stop after first job that wasn't paused/propagating/etc if self.__top_only: return def register_article(self, article, found=True): """ Register the articles we tried Not locked for performance, since it only modifies individual NZOs """ nzf = article.nzf nzo = nzf.nzo if nzf.deleted: logging.debug("Discarding article %s, no longer in queue", article.article) return file_done, post_done = nzo.remove_article(article, found) filename = nzf.filename if nzo.is_gone(): logging.debug('Discarding article %s for deleted job', filename) else: if file_done: if nzo.next_save is None or time.time() > nzo.next_save: nzo.save_to_disk() BPSMeter.do.save() if nzo.save_timeout is None: nzo.next_save = None else: nzo.next_save = time.time() + nzo.save_timeout if not nzo.precheck: _type = nzf.type # Only start decoding if we have a filename and type if filename and _type: Assembler.do.process((nzo, nzf)) elif filename.lower().endswith('.par2'): # Broken par2 file, try to get another one nzo.promote_par2(nzf) else: if file_has_articles(nzf): logging.warning(T('%s -> Unknown encoding'), filename) if post_done: self.end_job(nzo) def end_job(self, nzo): """ Send NZO to the post-processing queue """ logging.info('[%s] Ending job %s', caller_name(), nzo.final_name) # Notify assembler to call postprocessor if not nzo.deleted: nzo.deleted = True if nzo.precheck: nzo.save_to_disk() # Check result enough, _ratio = nzo.check_quality() if enough: # Enough data present, do real download self.cleanup_nzo(nzo, keep_basic=True) self.send_back(nzo) return else: # Not enough data, let postprocessor show it as failed pass Assembler.do.process((nzo, None)) def actives(self, grabs=True): """ Return amount of non-paused jobs, optionally with 'grabbing' items Not locked for performance, only reads the queue """ n = 0 for nzo in self.__nzo_list: # Ignore any items that are paused if grabs and nzo.status == Status.GRABBING: n += 1 elif nzo.status not in (Status.PAUSED, Status.GRABBING): n += 1 return n def queue_info(self, search=None, start=0, limit=0): """ Return list of queued jobs, optionally filtered by 'search' and limited by start and limit. Not locked for performance, only reads the queue """ if search: search = search.lower() bytes_left = 0 bytes_total = 0 bytes_left_previous_page = 0 q_size = 0 pnfo_list = [] n = 0 for nzo in self.__nzo_list: if nzo.status not in (Status.PAUSED, Status.CHECKING) or nzo.priority == TOP_PRIORITY: b_left = nzo.remaining bytes_total += nzo.bytes bytes_left += b_left q_size += 1 # We need the number of bytes before the current page if n < start: bytes_left_previous_page += b_left if (not search) or search in nzo.final_name_pw_clean.lower(): if (not limit) or (start <= n < start + limit): pnfo_list.append(nzo.gather_info()) n += 1 if not search: n = len(self.__nzo_list) return QNFO(bytes_total, bytes_left, bytes_left_previous_page, pnfo_list, q_size, n) def remaining(self): """ Return bytes left in the queue by non-paused items Not locked for performance, only reads the queue """ bytes_left = 0 for nzo in self.__nzo_list: if nzo.status != 'Paused': bytes_left += nzo.remaining return bytes_left def is_empty(self): empty = True for nzo in self.__nzo_list: if not nzo.futuretype and nzo.status != 'Paused': empty = False break return empty def cleanup_nzo(self, nzo, keep_basic=False, del_files=False): # Abort DirectUnpack and let it remove files nzo.abort_direct_unpacker() nzo.purge_data(keep_basic, del_files) ArticleCache.do.purge_articles(nzo.saved_articles) def stop_idle_jobs(self): """ Detect jobs that have zero files left and send them to post processing """ empty = [] for nzo in self.__nzo_list: if not nzo.futuretype and not nzo.files and nzo.status not in (Status.PAUSED, Status.GRABBING): logging.info('Found idle job %s', nzo.final_name) empty.append(nzo) # Stall prevention by checking if all servers are in the trylist # This is a CPU-cheaper alternative to prevent stalling if len(nzo.try_list) == sabnzbd.downloader.Downloader.do.server_nr: # Maybe the NZF's need a reset too? for nzf in nzo.files: if len(nzf.try_list) == sabnzbd.downloader.Downloader.do.server_nr: # We do not want to reset all article trylists, they are good logging.info('Resetting bad trylist for file %s in job %s', nzf.filename, nzo.final_name) nzf.reset_try_list() # Reset main trylist, minimal performance impact logging.info('Resetting bad trylist for job %s', nzo.final_name) nzo.reset_try_list() for nzo in empty: self.end_job(nzo) def pause_on_prio(self, priority): for nzo in self.__nzo_list: if nzo.priority == priority: nzo.pause() @NzbQueueLocker def resume_on_prio(self, priority): for nzo in self.__nzo_list: if nzo.priority == priority: # Don't use nzo.resume() to avoid resetting job warning flags nzo.status = Status.QUEUED def pause_on_cat(self, cat): for nzo in self.__nzo_list: if nzo.cat == cat: nzo.pause() @NzbQueueLocker def resume_on_cat(self, cat): for nzo in self.__nzo_list: if nzo.cat == cat: # Don't use nzo.resume() to avoid resetting job warning flags nzo.status = Status.QUEUED def get_urls(self): """ Return list of future-types needing URL """ lst = [] for nzo_id in self.__nzo_table: nzo = self.__nzo_table[nzo_id] if nzo.futuretype: url = nzo.url if nzo.futuretype and url.lower().startswith('http'): lst.append((url, nzo)) return lst def __repr__(self): return "" def _nzo_date_cmp(nzo1, nzo2): avg_date1 = nzo1.avg_date avg_date2 = nzo2.avg_date if avg_date1 is None and avg_date2 is None: return 0 if avg_date1 is None: avg_date1 = datetime.datetime.now() elif avg_date2 is None: avg_date2 = datetime.datetime.now() return cmp(avg_date1, avg_date2) def _nzo_name_cmp(nzo1, nzo2): return cmp(nzo1.final_name.lower(), nzo2.final_name.lower()) def _nzo_size_cmp(nzo1, nzo2): return cmp(nzo1.bytes, nzo2.bytes) def sort_queue_function(nzo_list, method, reverse): ultra_high_priority = [nzo for nzo in nzo_list if nzo.priority == REPAIR_PRIORITY] super_high_priority = [nzo for nzo in nzo_list if nzo.priority == TOP_PRIORITY] high_priority = [nzo for nzo in nzo_list if nzo.priority == HIGH_PRIORITY] normal_priority = [nzo for nzo in nzo_list if nzo.priority == NORMAL_PRIORITY] low_priority = [nzo for nzo in nzo_list if nzo.priority == LOW_PRIORITY] ultra_high_priority.sort(cmp=method, reverse=reverse) super_high_priority.sort(cmp=method, reverse=reverse) high_priority.sort(cmp=method, reverse=reverse) normal_priority.sort(cmp=method, reverse=reverse) low_priority.sort(cmp=method, reverse=reverse) new_list = ultra_high_priority new_list.extend(super_high_priority) new_list.extend(high_priority) new_list.extend(normal_priority) new_list.extend(low_priority) # Make sure any left-over jobs enter the new list for item in nzo_list: if item not in new_list: new_list.append(item) return new_list SABnzbd-2.3.2/sabnzbd/nzbstuff.py0000644000000000000000000024134213217005257014775 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.nzbstuff - misc """ # Standard Library import os import time import re import logging import datetime import threading import xml.sax import xml.sax.handler import xml.sax.xmlreader import hashlib import difflib try: from cStringIO import StringIO except ImportError: from StringIO import StringIO # SABnzbd modules import sabnzbd from sabnzbd.constants import GIGI, ATTRIB_FILE, JOB_ADMIN, \ REPAIR_PRIORITY, TOP_PRIORITY, HIGH_PRIORITY, NORMAL_PRIORITY, \ LOW_PRIORITY, DEFAULT_PRIORITY, PAUSED_PRIORITY, DUP_PRIORITY, STOP_PRIORITY, \ RENAMES_FILE, MAX_BAD_ARTICLES, Status, PNFO from sabnzbd.misc import to_units, cat_to_opts, cat_convert, sanitize_foldername, \ get_unique_path, get_admin_path, remove_all, sanitize_filename, globber_full, \ int_conv, set_permissions, format_time_string, long_path, trim_win_path, \ fix_unix_encoding, calc_age, is_obfuscated_filename, get_ext, get_filename, \ get_unique_filename, renamer, remove_file, remove_dir, caller_name from sabnzbd.decorators import synchronized import sabnzbd.config as config import sabnzbd.cfg as cfg from sabnzbd.encoding import unicoder, platform_encode from sabnzbd.database import HistoryDB from sabnzbd.rating import Rating __all__ = ['Article', 'NzbFile', 'NzbObject'] # Name patterns SUBJECT_FN_MATCHER = re.compile(r'"([^"]*)"') RE_NORMAL_NAME = re.compile(r'\.\w{1,5}$') # Test reasonably sized extension at the end RE_QUICK_PAR2_CHECK = re.compile(r'\.par2\W*', re.I) RE_RAR = re.compile(r'(\.rar|\.r\d\d|\.s\d\d|\.t\d\d|\.u\d\d|\.v\d\d)$', re.I) RE_PROPER = re.compile(r'(^|[\. _-])(PROPER|REAL|REPACK)([\. _-]|$)') ############################################################################## # Trylist ############################################################################## TRYLIST_LOCK = threading.Lock() class TryList(object): """ TryList keeps track of which servers have been tried for a specific article """ # Pre-define attributes to save memory __slots__ = ('try_list', 'fetcher_priority') def __init__(self): self.try_list = [] self.fetcher_priority = 0 def server_in_try_list(self, server): """ Return whether specified server has been tried """ with TRYLIST_LOCK: return server in self.try_list def add_to_try_list(self, server): """ Register server as having been tried already """ with TRYLIST_LOCK: if server not in self.try_list: self.try_list.append(server) def reset_try_list(self): """ Clean the list """ with TRYLIST_LOCK: self.try_list = [] def __getstate__(self): """ Save the servers """ return [server.id for server in self.try_list] def __setstate__(self, servers_ids): self.try_list = [] for server_id in servers_ids: if server_id in sabnzbd.downloader.Downloader.do.server_dict: self.add_to_try_list(sabnzbd.downloader.Downloader.do.server_dict[server_id]) ############################################################################## # Article ############################################################################## ArticleSaver = ( 'article', 'art_id', 'bytes', 'partnum', 'lowest_partnum', 'nzf' ) class Article(TryList): """ Representation of one article """ # Pre-define attributes to save memory __slots__ = ArticleSaver + ('fetcher', 'fetcher_priority', 'tries') def __init__(self, article, bytes, partnum, nzf): TryList.__init__(self) self.fetcher = None self.article = article self.art_id = None self.bytes = bytes self.partnum = partnum self.lowest_partnum = False self.tries = 0 # Try count self.nzf = nzf def get_article(self, server, servers): """ Return article when appropriate for specified server """ log = sabnzbd.LOG_ALL if not self.fetcher and not self.server_in_try_list(server): if log: logging.debug('Article %s | Server: %s | in second if', self.article, server.host) # Is the current selected server of the same priority as this article? if log: logging.debug('Article %s | Server: %s | Article priority: %s', self.article, server.host, self.fetcher_priority) if log: logging.debug('Article %s | Server: %s | Server priority: %s', self.article, server.host, server.priority) if server.priority == self.fetcher_priority: if log: logging.debug('Article %s | Server: %s | same priority, use it', self.article, server.host) self.fetcher = server self.tries += 1 if log: logging.debug('Article %s | Server: %s | Article-try: %s', self.article, server.host, self.tries) return self else: if log: logging.debug('Article %s | Server: %s | not the same priority', self.article, server.host) # No, so is it a lower priority? if server.priority > self.fetcher_priority: if log: logging.debug('Article %s | Server: %s | lower priority', self.article, server.host) # Is there an available server that is a higher priority? found_priority = 1000 # for server_check in config.get_servers(): for server_check in servers: if log: logging.debug('Article %s | Server: %s | checking', self.article, server.host) # if (server_check.priority() < found_priority and server_check.priority() < server.priority and not self.server_in_try_list(server_check)): if server_check.active and (server_check.priority < found_priority): if server_check.priority < server.priority: if (not self.server_in_try_list(server_check)): if log: logging.debug('Article %s | Server: %s | setting found priority to %s', self.article, server.host, server_check.priority) found_priority = server_check.priority if found_priority == 1000: # If no higher priority servers, use this server self.fetcher_priority = server.priority self.fetcher = server self.tries += 1 if log: logging.debug('Article %s | Server: %s | Article-try: %s', self.article, server.host, self.tries) return self else: # There is a higher priority server, so set article priority if log: logging.debug('Article %s | Server: %s | setting self priority', self.article, server.host) self.fetcher_priority = found_priority if log: logging.debug('Article %s | Server: %s | Returning None', self.article, server.host) return None def get_art_id(self): """ Return unique article storage name, create if needed """ if not self.art_id: self.art_id = sabnzbd.get_new_id("article", self.nzf.nzo.workpath) return self.art_id def __getstate__(self): """ Save to pickle file, selecting attributes """ dict_ = {} for item in ArticleSaver: dict_[item] = getattr(self, item) dict_['try_list'] = TryList.__getstate__(self) return dict_ def __setstate__(self, dict_): """ Load from pickle file, selecting attributes """ for item in ArticleSaver: try: setattr(self, item, dict_[item]) except KeyError: # Handle new attributes setattr(self, item, None) TryList.__setstate__(self, dict_.get('try_list', [])) self.fetcher_priority = 0 self.fetcher = None self.tries = 0 def __repr__(self): return "" % \ (self.article, self.bytes, self.partnum, self.art_id) ############################################################################## # NzbFile ############################################################################## NzbFileSaver = ( 'date', 'subject', 'filename', 'filename_checked', 'type', 'is_par2', 'vol', 'blocks', 'setname', 'articles', 'decodetable', 'bytes', 'bytes_left', 'article_count', 'nzo', 'nzf_id', 'deleted', 'valid', 'import_finished', 'md5sum', 'md5of16k' ) class NzbFile(TryList): """ Representation of one file consisting of multiple articles """ # Pre-define attributes to save memory __slots__ = NzbFileSaver def __init__(self, date, subject, article_db, bytes, nzo): """ Setup object """ TryList.__init__(self) self.date = date self.subject = subject self.type = None self.filename = name_extractor(subject) self.filename_checked = False self.is_par2 = False self.vol = None self.blocks = None self.setname = None self.articles = [] self.decodetable = {} self.bytes = bytes self.bytes_left = bytes self.article_count = 0 self.nzo = nzo self.nzf_id = sabnzbd.get_new_id("nzf", nzo.workpath) self.deleted = False self.valid = False self.import_finished = False self.md5sum = None self.md5of16k = None self.valid = bool(article_db) if self.valid and self.nzf_id: # Save first article seperate, but not for all but first par2 file # Non-par2 files and the first par2 will have no volume and block number # When DirectUnpack is disabled, do not do any of this to also preserve disk IO setname, vol, block = sabnzbd.par2file.analyse_par2(self.filename) if cfg.direct_unpack() and not vol and not block: first_num = min(article_db.keys()) first_article = self.add_article(article_db.pop(first_num), first_num) first_article.lowest_partnum = True self.nzo.first_articles.append(first_article) # Any articles left? if article_db: # Save the rest sabnzbd.save_data(article_db, self.nzf_id, nzo.workpath) else: # All imported self.import_finished = True def finish_import(self): """ Load the article objects from disk """ logging.debug("Finishing import on %s", self.subject) article_db = sabnzbd.load_data(self.nzf_id, self.nzo.workpath, remove=False) if article_db: for partnum in article_db: self.add_article(article_db[partnum], partnum) # Make sure we have labeled the lowest part number # Also when DirectUnpack is disabled we need to know self.decodetable[min(self.decodetable)].lowest_partnum = True # Mark safe to continue self.import_finished = True def add_article(self, article_info, partnum): """ Add article to object database and return article object """ article = Article(article_info[0], article_info[1], partnum, self) self.articles.append(article) self.decodetable[partnum] = article return article def remove_article(self, article, found): """ Handle completed article, possibly end of file """ if article in self.articles: self.articles.remove(article) if found: self.bytes_left -= article.bytes return (not self.articles) def set_par2(self, setname, vol, blocks): """ Designate this this file as a par2 file """ self.is_par2 = True self.setname = setname self.vol = vol self.blocks = int(blocks) def get_article(self, server, servers): """ Get next article to be downloaded """ for article in self.articles: article = article.get_article(server, servers) if article: return article self.add_to_try_list(server) def reset_all_try_lists(self): """ Clear all lists of visited servers """ for art in self.articles: art.reset_try_list() self.reset_try_list() @property def completed(self): """ Is this file completed? """ return self.import_finished and not bool(self.articles) def remove_admin(self): """ Remove article database from disk (sabnzbd_nzf_)""" try: logging.debug('Removing article database for %s', self.nzf_id) remove_file(os.path.join(self.nzo.workpath, self.nzf_id)) except: pass def __getstate__(self): """ Save to pickle file, selecting attributes """ dict_ = {} for item in NzbFileSaver: dict_[item] = getattr(self, item) dict_['try_list'] = TryList.__getstate__(self) return dict_ def __setstate__(self, dict_): """ Load from pickle file, selecting attributes """ for item in NzbFileSaver: try: setattr(self, item, dict_[item]) except KeyError: # Handle new attributes setattr(self, item, None) TryList.__setstate__(self, dict_.get('try_list', [])) def __repr__(self): return "" % (self.filename, self.type) ############################################################################## # NzbParser ############################################################################## class NzbParser(xml.sax.handler.ContentHandler): """ Forgiving parser for NZB's """ def __init__(self, nzo): self.nzo = nzo self.in_nzb = False self.in_file = False self.in_groups = False self.in_group = False self.in_segments = False self.in_segment = False self.in_head = False self.in_meta = False self.meta_type = '' self.meta_types = {} self.meta_content = [] self.filename = '' self.avg_age = 0 self.valids = 0 self.skipped_files = 0 self.nzf_list = [] self.groups = [] self.md5 = hashlib.md5() self.now = time.time() def startDocument(self): pass def startElement(self, name, attrs): if name == 'segment' and self.in_nzb and self.in_file and self.in_segments: try: self.seg_bytes = int(attrs.get('bytes')) self.article_nr = int(attrs.get('number')) except ValueError: return self.article_id = [] self.in_segment = True elif name == 'segments' and self.in_nzb and self.in_file: self.in_segments = True elif name == 'file' and self.in_nzb: subject = attrs.get('subject', '').strip() self.filename = subject self.in_file = True self.fileSubject = subject try: self.file_date = int(attrs.get('date')) except: # NZB has non-standard timestamp, assume now self.file_date = self.now self.article_db = {} self.file_bytes = 0 elif name == 'group' and self.in_nzb and self.in_file and self.in_groups: self.in_group = True self.group_name = [] elif name == 'groups' and self.in_nzb and self.in_file: self.in_groups = True elif name == 'head' and self.in_nzb: self.in_head = True elif name == 'meta' and self.in_nzb and self.in_head: self.in_meta = True meta_type = attrs.get('type') if meta_type: self.meta_type = meta_type.lower() self.meta_content = [] elif name == 'nzb': self.in_nzb = True def characters(self, content): if self.in_group: self.group_name.append(content) elif self.in_segment: self.article_id.append(content) elif self.in_meta: self.meta_content.append(content) def endElement(self, name): if name == 'group' and self.in_group: group = str(''.join(self.group_name)) if group not in self.groups: self.groups.append(group) self.in_group = False elif name == 'segment' and self.in_segment: partnum = self.article_nr segm = str(''.join(self.article_id)) self.md5.update(segm) if partnum in self.article_db: if segm != self.article_db[partnum][0]: msg = 'Duplicate part %s, but different ID-s (%s // %s)' % (partnum, self.article_db[partnum][0], segm) logging.info(msg) self.nzo.increase_bad_articles_counter('duplicate_articles') else: logging.info("Skipping duplicate article (%s)", segm) else: self.article_db[partnum] = (segm, self.seg_bytes) self.file_bytes += self.seg_bytes self.in_segment = False elif name == 'groups' and self.in_groups: self.in_groups = False elif name == 'segments' and self.in_segments: self.in_segments = False elif name == 'file' and self.in_file: # Create an NZF self.in_file = False if not self.article_db: logging.warning(T('File %s is empty, skipping'), self.filename) return try: tm = datetime.datetime.fromtimestamp(self.file_date) except: tm = datetime.datetime.fromtimestamp(self.now) self.file_date = self.now nzf = NzbFile(tm, self.filename, self.article_db, self.file_bytes, self.nzo) # Check if file was added with same name if cfg.reject_duplicate_files(): nzo_matches = filter(lambda x: (x.filename == nzf.filename), self.nzo.files) if nzo_matches: logging.info('File %s occured twice in NZB, discarding smaller file', nzf.filename) # Which is smaller? Current or old one if nzo_matches[0].bytes >= nzf.bytes: # Skip this new one return else: # Have to remove the old one but still add the new one self.nzo.files.remove(nzo_matches[0]) del self.nzo.files_table[nzo_matches[0].nzf_id] self.nzo.bytes -= nzo_matches[0].bytes self.avg_age -= time.mktime(nzo_matches[0].date.timetuple()) self.valids -= 1 self.nzf_list.remove(nzo_matches[0]) if nzf.valid and nzf.nzf_id: logging.info('File %s - %s added to queue', nzf.filename, nzf.nzf_id) self.nzo.files.append(nzf) self.nzo.files_table[nzf.nzf_id] = nzf self.nzo.bytes += nzf.bytes self.avg_age += self.file_date self.valids += 1 self.nzf_list.append(nzf) else: logging.info('Error importing %s, skipping', self.filename) if nzf.nzf_id: sabnzbd.remove_data(nzf.nzf_id, self.nzo.workpath) self.skipped_files += 1 elif name == 'head': self.in_head = False elif name == 'meta': self.in_meta = False if self.meta_type: if self.meta_type not in self.meta_types: self.meta_types[self.meta_type] = [] self.meta_types[self.meta_type].append(''.join(self.meta_content)) elif name == 'nzb': self.in_nzb = False def endDocument(self): """ End of the file """ self.nzo.groups = self.groups self.nzo.meta = self.meta_types logging.debug('META-DATA = %s', self.nzo.meta) files = max(1, self.valids) self.nzo.avg_stamp = self.avg_age / files self.nzo.avg_date = datetime.datetime.fromtimestamp(self.avg_age / files) self.nzo.md5sum = self.md5.hexdigest() if self.skipped_files: logging.warning(T('Failed to import %s files from %s'), self.skipped_files, self.nzo.filename) ############################################################################## # NzbObject ############################################################################## NzbObjectSaver = ( 'filename', 'work_name', 'final_name', 'created', 'bytes', 'bytes_downloaded', 'bytes_tried', 'bytes_missing', 'repair', 'unpack', 'delete', 'script', 'cat', 'url', 'groups', 'avg_date', 'md5of16k', 'partable', 'extrapars', 'md5packs', 'files', 'files_table', 'finished_files', 'status', 'avg_bps_freq', 'avg_bps_total', 'priority', 'saved_articles', 'nzo_id', 'futuretype', 'deleted', 'parsed', 'action_line', 'unpack_info', 'fail_msg', 'nzo_info', 'custom_name', 'password', 'next_save', 'save_timeout', 'encrypted', 'bad_articles', 'duplicate', 'oversized', 'precheck', 'incomplete', 'reuse', 'meta', 'first_articles', 'md5sum', 'servercount', 'unwanted_ext', 'renames', 'rating_filtered' ) # Lock to prevent errors when saving the NZO data NZO_LOCK = threading.RLock() class NzbObject(TryList): def __init__(self, filename, pp, script, nzb=None, futuretype=False, cat=None, url=None, priority=NORMAL_PRIORITY, nzbname=None, status="Queued", nzo_info=None, reuse=False, dup_check=True): TryList.__init__(self) filename = platform_encode(filename) nzbname = platform_encode(nzbname) if pp is None: r = u = d = None else: r, u, d = sabnzbd.pp_to_opts(pp) self.filename = filename # Original filename if nzbname and nzb: work_name = nzbname # Use nzbname if set and only for non-future slot else: work_name = filename # If non-future: create safe folder name stripped from ".nzb" and junk if nzb and work_name and work_name.lower().endswith('.nzb'): dname, ext = os.path.splitext(work_name) # Used for folder name for final unpack if ext.lower() == '.nzb': work_name = dname work_name, password = scan_password(work_name) if not work_name: work_name = filename if nzb and work_name and not reuse: work_name = sanitize_foldername(work_name) if not work_name: # In case only /password was entered for nzbname work_name = filename # Check for password also in filename if not password: dummy, password = scan_password(os.path.splitext(filename)[0]) # Remove trailing .nzb and .par(2) self.work_name = create_work_name(work_name) self.final_name = create_work_name(work_name) self.meta = {} self.servercount = {} # Dict to keep bytes per server self.created = False # dirprefixes + work_name created self.direct_unpacker = None # Holds the DirectUnpacker instance self.bytes = 0 # Original bytesize self.bytes_downloaded = 0 # Downloaded byte self.bytes_tried = 0 # Which bytes did we try self.bytes_missing = 0 # Bytes missing self.bad_articles = 0 # How many bad (non-recoverable) articles self.set_priority(priority) # Parse priority of input self.repair = r # True if we want to repair this set self.unpack = u # True if we want to unpack this set self.delete = d # True if we want to delete this set self.script = script # External script for this set self.cat = cat # Indexer category if url: self.url = str(url) # Source URL else: self.url = filename self.groups = [] self.avg_date = datetime.datetime.fromtimestamp(0.0) self.avg_stamp = 0.0 # Avg age in seconds (calculated from avg_age) self.partable = {} # Holds one parfile-name for each set self.extrapars = {} # Holds the extra parfile names for all sets self.md5packs = {} # Holds the md5pack for each set (name: hash) self.md5of16k = {} # Holds the md5s of the first-16k of all files in the NZB (hash: name) self.files = [] # List of all NZFs self.files_table = {} # Dictionary of NZFs indexed using NZF_ID self.renames = {} # Dictionary of all renamed files self.finished_files = [] # List of all finished NZFs # the current status of the nzo eg: # Queued, Downloading, Repairing, Unpacking, Failed, Complete self.status = status self.avg_bps_freq = 0 self.avg_bps_total = 0 self.first_articles = [] self.saved_articles = [] self.nzo_id = None self.futuretype = futuretype self.deleted = False self.to_be_removed = False self.parsed = False self.duplicate = False self.oversized = False self.precheck = False self.incomplete = False self.unwanted_ext = 0 self.rating_filtered = 0 self.reuse = reuse if self.status == Status.QUEUED and not reuse: self.precheck = cfg.pre_check() if self.precheck: self.status = Status.CHECKING # Store one line responses for filejoin/par2/unrar/unzip here for history display self.action_line = '' # Store the results from various filejoin/par2/unrar/unzip stages self.unpack_info = {} # Stores one line containing the last failure self.fail_msg = '' # Stores various info about the nzo to be if nzo_info: self.nzo_info = nzo_info else: self.nzo_info = {} # Temporary store for custom foldername - needs to be stored because of url fetching self.custom_name = nzbname self.password = password self.next_save = None self.save_timeout = None self.encrypted = 0 self.url_wait = None self.url_tries = 0 self.pp_active = False # Signals active post-processing (not saved) self.md5sum = None if nzb is None: # This is a slot for a future NZB, ready now return # Apply conversion option to final folder if cfg.replace_spaces(): logging.info('Replacing spaces with underscores in %s', self.final_name) self.final_name = self.final_name.replace(' ', '_') if cfg.replace_dots(): logging.info('Replacing dots with spaces in %s', self.final_name) self.final_name = self.final_name.replace('.', ' ') # Determine "incomplete" folder wdir = long_path(os.path.join(cfg.download_dir.get_path(), self.work_name)) adir = os.path.join(wdir, JOB_ADMIN) # Check against identical checksum or series/season/episode if (not reuse) and nzb and dup_check and priority != REPAIR_PRIORITY: duplicate, series = self.has_duplicates() else: duplicate = series = 0 if reuse: remove_all(adir, 'SABnzbd_nz?_*', True) remove_all(adir, 'SABnzbd_article_*', True) else: wdir = trim_win_path(wdir) wdir = get_unique_path(wdir, create_dir=True) set_permissions(wdir) adir = os.path.join(wdir, JOB_ADMIN) if not os.path.exists(adir): os.mkdir(adir) dummy, self.work_name = os.path.split(wdir) self.created = True # Must create a lower level XML parser because we must # disable the reading of the DTD file from an external website # by setting "feature_external_ges" to 0. if nzb and '' not in nzb: logging.warning(T('Incomplete NZB file %s'), filename) else: logging.warning(T('Invalid NZB file %s, skipping (reason=%s, line=%s)'), filename, err.getMessage(), err.getLineNumber()) except Exception, err: self.incomplete = True logging.warning(T('Invalid NZB file %s, skipping (reason=%s, line=%s)'), filename, err, 0) if self.incomplete: if cfg.allow_incomplete_nzb(): self.pause() else: self.purge_data() raise ValueError sabnzbd.backup_nzb(filename, nzb) sabnzbd.save_compressed(adir, filename, nzb) if not self.files and not reuse: self.purge_data(keep_basic=False) if cfg.warn_empty_nzb(): mylog = logging.warning else: mylog = logging.info if self.url: mylog(T('Empty NZB file %s') + ' [%s]', filename, self.url) else: mylog(T('Empty NZB file %s'), filename) raise ValueError if cat is None: for metacat in self.meta.get('category', ()): metacat = cat_convert(metacat) if metacat: cat = metacat break if cat is None: for grp in self.groups: cat = cat_convert(grp) if cat: break # Pickup backed-up attributes when re-using if reuse: cat, pp, script, priority, name, password, self.url = get_attrib_file(self.workpath, 7) cat = unicoder(cat, True) script = unicoder(script, True) if name: self.final_name = unicoder(name, True) if password: self.password = unicoder(password, True) # Determine category and find pp/script values self.cat, pp_tmp, self.script, priority = cat_to_opts(cat, pp, script, priority) self.set_priority(priority) self.repair, self.unpack, self.delete = sabnzbd.pp_to_opts(pp_tmp) # Run user pre-queue script if needed if not reuse and cfg.pre_script(): accept, name, pp, cat_pp, script_pp, priority, group = \ sabnzbd.newsunpack.pre_queue(self.final_name_pw_clean, pp, cat, script, priority, self.bytes, self.groups) # Accept or reject accept = int_conv(accept) if accept < 1: self.purge_data() raise TypeError if accept == 2: self.fail_msg = T('Pre-queue script marked job as failed') # Process all options, only over-write if set by script # Beware that cannot do "if priority/pp", because those can # also have a valid value of 0, which shouldn't be ignored if name: self.set_final_name_pw(name) try: pp = int(pp) except: pp = None if cat_pp: cat = cat_pp try: priority = int(priority) except: priority = DEFAULT_PRIORITY if script_pp: script = script_pp if group: self.groups = [str(group)] # Re-evaluate results from pre-queue script self.cat, pp, self.script, priority = cat_to_opts(cat, pp, script, priority) self.set_priority(priority) self.repair, self.unpack, self.delete = sabnzbd.pp_to_opts(pp) else: accept = 1 # Pause job when above size limit limit = cfg.size_limit.get_int() if not reuse and abs(limit) > 0.5 and self.bytes > limit: logging.info('Job too large, forcing low prio and paused (%s)', self.work_name) self.pause() self.oversized = True self.priority = LOW_PRIORITY if duplicate and ((not series and cfg.no_dupes() == 1) or (series and cfg.no_series_dupes() == 1)): if cfg.warn_dupl_jobs(): logging.warning(T('Ignoring duplicate NZB "%s"'), filename) self.purge_data(keep_basic=False) raise TypeError if duplicate and ((not series and cfg.no_dupes() == 3) or (series and cfg.no_series_dupes() == 3)): if cfg.warn_dupl_jobs(): logging.warning(T('Failing duplicate NZB "%s"'), filename) # Move to history, utilizing the same code as accept&fail from pre-queue script self.fail_msg = T('Duplicate NZB') accept = 2 duplicate = False if duplicate or self.priority == DUP_PRIORITY: if cfg.no_dupes() == 4 or cfg.no_series_dupes() == 4: if cfg.warn_dupl_jobs(): logging.warning('%s: "%s"', T('Duplicate NZB'), filename) self.duplicate = True self.priority = NORMAL_PRIORITY else: if cfg.warn_dupl_jobs(): logging.warning(T('Pausing duplicate NZB "%s"'), filename) self.duplicate = True self.pause() self.priority = NORMAL_PRIORITY if self.priority == PAUSED_PRIORITY: self.pause() self.priority = NORMAL_PRIORITY if reuse: self.check_existing_files(wdir) # Perform sorting self.sort_nzfs() # Copy meta fields to nzo_info, if not already set for kw in self.meta: if not self.nzo_info.get(kw): self.nzo_info[kw] = self.meta[kw][0] # Show first meta-password (if any), when there's no explicit password if not self.password and self.meta.get('password'): self.password = self.meta.get('password', [None])[0] # Set nzo save-delay to minimum 120 seconds self.save_timeout = max(120, min(6.0 * float(self.bytes) / GIGI, 300.0)) # In case pre-queue script or duplicate check want to move # to history we first need an nzo_id by entering the NzbQueue if accept == 2: self.deleted = True self.status = Status.FAILED sabnzbd.NzbQueue.do.add(self, quiet=True) sabnzbd.NzbQueue.do.end_job(self) # Raise error, so it's not added raise TypeError @synchronized(NZO_LOCK) def update_download_stats(self, bps, serverid, bytes): if bps: self.avg_bps_total += bps / 1024 self.avg_bps_freq += 1 if serverid in self.servercount: self.servercount[serverid] += bytes else: self.servercount[serverid] = bytes @synchronized(NZO_LOCK) def remove_nzf(self, nzf): if nzf in self.files: self.files.remove(nzf) if nzf not in self.finished_files: self.finished_files.append(nzf) nzf.import_finished = True nzf.deleted = True return not bool(self.files) def sort_nzfs(self): """ Sort the files in the NZO, respecting date sorting and unwanted extensions """ if cfg.auto_sort(): self.files.sort(cmp=nzf_cmp_date) else: self.files.sort(cmp=nzf_cmp_name) # In the hunt for Unwanted Extensions: # The file with the unwanted extension often is in the first or the last rar file # So put the last rar immediately after the first rar file so that it gets detected early if cfg.unwanted_extensions() and not cfg.auto_sort(): # ... only useful if there are unwanted extensions defined and there is no sorting on date logging.debug('Unwanted Extension: putting last rar after first rar') nzfposcounter = firstrarpos = lastrarpos = 0 for nzf in self.files: nzfposcounter += 1 if '.rar' in str(nzf): # a NZF found with '.rar' in the name if firstrarpos == 0: # this is the first .rar found, so remember this position firstrarpos = nzfposcounter lastrarpos = nzfposcounter lastrarnzf = nzf # The NZF itself if firstrarpos != lastrarpos: # at least two different .rar's found logging.debug('Unwanted Extension: First rar at %s, Last rar at %s', firstrarpos, lastrarpos) logging.debug('Unwanted Extension: Last rar is %s', str(lastrarnzf)) try: self.files.remove(lastrarnzf) # first remove. NB: remove() does searches for lastrarnzf self.files.insert(firstrarpos, lastrarnzf) # ... and only then add after position firstrarpos except: logging.debug('The lastrar swap did not go well') def reset_all_try_lists(self): for nzf in self.files: nzf.reset_all_try_lists() self.reset_try_list() @synchronized(NZO_LOCK) def postpone_pars(self, nzf, parset): """ Move all vol-par files matching 'parset' to the extrapars table """ # Create new extrapars if it didn't already exist # For example if created when the first par2 file was missing if parset not in self.extrapars: self.extrapars[parset] = [] # Set this one as the main one self.partable[parset] = nzf lparset = parset.lower() for xnzf in self.files[:]: name = xnzf.filename or platform_encode(xnzf.subject) # Move only when not current NZF and filename was extractable from subject if name: setname, vol, block = sabnzbd.par2file.analyse_par2(name) # Don't postpone header-only-files, to extract all possible md5of16k if setname and block and matcher(lparset, setname.lower()): xnzf.set_par2(parset, vol, block) # Don't postpone if all par2 are desired and should be kept or not repairing if self.repair and not(cfg.enable_all_par() and not cfg.enable_par_cleanup()): self.extrapars[parset].append(xnzf) self.files.remove(xnzf) # Already count these bytes as done self.bytes_tried += xnzf.bytes_left # Sort the sets for setname in self.extrapars: self.extrapars[parset].sort(key=lambda x: x.blocks) # Also re-parse all filenames in case par2 came after first articles self.verify_all_filenames_and_resort() @synchronized(NZO_LOCK) def handle_par2(self, nzf, filepath): """ Check if file is a par2 and build up par2 collection """ # Need to remove it from the other set it might be in self.remove_extrapar(nzf) # Reparse setname, vol, block = sabnzbd.par2file.analyse_par2(nzf.filename, filepath) nzf.set_par2(setname, vol, block) # Parse the file contents for hashes pack = sabnzbd.par2file.parse_par2_file(nzf, filepath) # If we couldn't parse it, we ignore it if pack: if pack not in self.md5packs.values(): logging.debug('Got md5pack for set %s', nzf.setname) self.md5packs[setname] = pack # See if we need to postpone some pars self.postpone_pars(nzf, setname) else: # Need to add this to the set, first need setname for setname in self.md5packs: if self.md5packs[setname] == pack: break # Change the properties nzf.set_par2(setname, vol, block) logging.debug('Got additional md5pack for set %s', nzf.setname) # Make sure it exists, could be removed by newsunpack if setname not in self.extrapars: self.extrapars[setname] = [] self.extrapars[setname].append(nzf) elif self.repair: # For some reason this par2 file is broken but we still want repair self.promote_par2(nzf) # Is it an obfuscated file? if get_ext(nzf.filename) != '.par2': # Do cheap renaming so it gets better picked up by par2 # Only basename has to be the same new_fname = get_unique_filename(os.path.join(self.downpath, '%s.par2' % setname)) renamer(filepath, new_fname) self.renamed_file(get_filename(new_fname), nzf.filename) nzf.filename = get_filename(new_fname) @synchronized(NZO_LOCK) def promote_par2(self, nzf): """ In case of a broken par2 or missing par2, move another of the same set to the top (if we can find it) """ setname, vol, block = sabnzbd.par2file.analyse_par2(nzf.filename) # Now we need to identify if we have more in this set if setname and self.repair: # Maybe it was the first one if setname not in self.extrapars: self.postpone_pars(nzf, setname) # Get the next one for new_nzf in self.extrapars[setname]: if not new_nzf.completed: self.add_parfile(new_nzf) # Add it to the top self.files.remove(new_nzf) self.files.insert(0, new_nzf) break def get_extra_blocks(self, setname, needed_blocks): """ We want par2-files of all sets that are similar to this one So that we also can handle multi-sets with duplicate filenames Block-table has as keys the nr-blocks Returns number of added blocks in case they are available """ logging.info('Need %s more blocks, checking blocks', needed_blocks) avail_blocks = 0 block_table = {} for setname_search in self.extrapars: # Do it for our set, or highlight matching one # We might catch to many par2's, but that's okay if setname_search == setname or difflib.SequenceMatcher(None, setname, setname_search).ratio() > 0.85: for nzf in self.extrapars[setname_search]: # Don't count extrapars that are completed already if nzf.completed: continue blocks = int_conv(nzf.blocks) if blocks not in block_table: block_table[blocks] = [] # We assume same block-vol-naming for each set avail_blocks += blocks block_table[blocks].append(nzf) logging.info('%s blocks available', avail_blocks) # Enough? if avail_blocks >= needed_blocks: added_blocks = 0 while added_blocks < needed_blocks: block_size = min(block_table.keys()) for new_nzf in block_table[block_size]: self.add_parfile(new_nzf) added_blocks += block_size block_table.pop(block_size) logging.info('Added %s blocks to %s', added_blocks, self.final_name) return added_blocks else: # Not enough return False @synchronized(NZO_LOCK) def remove_article(self, article, found): nzf = article.nzf # First or regular article? if article.lowest_partnum and self.first_articles and article in self.first_articles: self.first_articles.remove(article) # All first articles done? if not self.first_articles and self.md5of16k: self.verify_all_filenames_and_resort() # Remove from file-tracking file_done = nzf.remove_article(article, found) # Only on fully loaded files we can say if it's really done if not nzf.import_finished: file_done = False # File completed, remove and do checks if file_done: self.remove_nzf(nzf) if not self.reuse and cfg.fail_hopeless_jobs() and not self.check_quality(99)[0]: # set the nzo status to return "Queued" self.status = Status.QUEUED self.set_download_report() self.fail_msg = T('Aborted, cannot be completed') + ' - https://sabnzbd.org/not-complete' self.set_unpack_info('Download', self.fail_msg, unique=False) logging.debug('Abort job "%s", due to impossibility to complete it', self.final_name_pw_clean) return True, True if not found: # Add extra parfiles when there was a damaged article and not pre-checking if self.extrapars and not self.precheck: self.prospective_add(nzf) # Sometimes a few CRC errors are still fine, so we continue if self.bad_articles > MAX_BAD_ARTICLES: self.abort_direct_unpacker() # Increase missing bytes counter self.bytes_missing += article.bytes else: # Increase counter of actually finished bytes self.bytes_downloaded += article.bytes # All the bytes that were tried self.bytes_tried += article.bytes post_done = False if not self.files: post_done = True # set the nzo status to return "Queued" self.status = Status.QUEUED self.set_download_report() return (file_done, post_done) @synchronized(NZO_LOCK) def remove_saved_article(self, article): self.saved_articles.remove(article) def check_existing_files(self, wdir): """ Check if downloaded files already exits, for these set NZF to complete """ fix_unix_encoding(wdir) # Get a list of already present files files = [os.path.basename(f) for f in globber_full(wdir) if os.path.isfile(f)] # Substitute renamed files renames = sabnzbd.load_data(RENAMES_FILE, self.workpath, remove=True) if renames: for name in renames: if name in files or renames[name] in files: if name in files: files.remove(name) files.append(renames[name]) self.renames = renames # Looking for the longest name first, minimizes the chance on a mismatch files.sort(lambda x, y: len(y) - len(x)) # The NZFs should be tried shortest first, to improve the chance on a proper match nzfs = self.files[:] nzfs.sort(lambda x, y: len(x.subject) - len(y.subject)) # Flag files from NZB that already exist as finished for filename in files[:]: for nzf in nzfs: subject = sanitize_filename(name_extractor(nzf.subject)) if (nzf.filename == filename) or (subject == filename) or (filename in subject): nzf.filename = filename nzf.bytes_left = 0 self.remove_nzf(nzf) nzfs.remove(nzf) files.remove(filename) # Set bytes correctly self.bytes_tried += nzf.bytes self.bytes_downloaded += nzf.bytes # Process par2 files filepath = os.path.join(wdir, filename) if sabnzbd.par2file.is_parfile(filepath): self.handle_par2(nzf, filepath) break # Create an NZF for each remaining existing file try: for filename in files: # Create NZB's using basic information filepath = os.path.join(wdir, filename) if os.path.exists(filepath): tup = os.stat(filepath) tm = datetime.datetime.fromtimestamp(tup.st_mtime) nzf = NzbFile(tm, filename, [], tup.st_size, self) self.files.append(nzf) self.files_table[nzf.nzf_id] = nzf nzf.filename = filename self.remove_nzf(nzf) # Set bytes correctly self.bytes += nzf.bytes self.bytes_tried += nzf.bytes self.bytes_downloaded += nzf.bytes # Process par2 files if sabnzbd.par2file.is_parfile(filepath): self.handle_par2(nzf, filepath) logging.info('Existing file %s added to job', filename) except: logging.debug('Bad NZB handling') logging.info("Traceback: ", exc_info=True) @property def pp(self): if self.repair is None: return None else: return sabnzbd.opts_to_pp(self.repair, self.unpack, self.delete) def set_pp(self, value): self.repair, self.unpack, self.delete = sabnzbd.pp_to_opts(value) logging.info('Set pp=%s for job %s', value, self.final_name) # Abort unpacking if not desired anymore if not self.unpack: self.abort_direct_unpacker() def set_priority(self, value): """ Check if this is a valid priority """ # When unknown (0 is a known one), set to DEFAULT if value == '' or value is None: self.priority = DEFAULT_PRIORITY return # Convert input value = int_conv(value) if value in (REPAIR_PRIORITY, TOP_PRIORITY, HIGH_PRIORITY, NORMAL_PRIORITY, \ LOW_PRIORITY, DEFAULT_PRIORITY, PAUSED_PRIORITY, DUP_PRIORITY, STOP_PRIORITY): self.priority = value return # Invalid value, set to normal priority self.priority = NORMAL_PRIORITY @property def final_name_labeled(self): prefix = '' if self.duplicate: prefix = T('DUPLICATE') + ' / ' # : Queue indicator for duplicate job if self.encrypted > 0 and self.status == 'Paused': prefix += T('ENCRYPTED') + ' / ' #: Queue indicator for encrypted job if self.oversized and self.status == 'Paused': prefix += T('TOO LARGE') + ' / ' # : Queue indicator for oversized job if self.incomplete and self.status == 'Paused': prefix += T('INCOMPLETE') + ' / ' # : Queue indicator for incomplete NZB if self.unwanted_ext and self.status == 'Paused': prefix += T('UNWANTED') + ' / ' # : Queue indicator for unwanted extensions if self.rating_filtered and self.status == 'Paused': prefix += T('FILTERED') + ' / ' # : Queue indicator for filtered if isinstance(self.url_wait, float): dif = int(self.url_wait - time.time() + 0.5) if dif > 0: prefix += T('WAIT %s sec') % dif + ' / ' # : Queue indicator for waiting URL fetch if (self.avg_stamp + float(cfg.propagation_delay() * 60)) > time.time() and self.priority != TOP_PRIORITY: wait_time = int((self.avg_stamp + float(cfg.propagation_delay() * 60) - time.time()) / 60 + 0.5) prefix += T('PROPAGATING %s min') % wait_time + ' / ' # : Queue indicator while waiting for propagation of post return '%s%s' % (prefix, self.final_name) @property def final_name_pw_clean(self): if self.password: return '%s / %s' % (self.final_name, self.password) else: return self.final_name def set_final_name_pw(self, name, password=None): if isinstance(name, basestring): if password is not None: name = platform_encode(name) self.password = platform_encode(password) else: name, password = scan_password(platform_encode(name)) if password is not None: self.password = password self.final_name = sanitize_foldername(name) self.save_to_disk() def pause(self): self.status = Status.PAUSED # Prevent loss of paused state when terminated if self.nzo_id and not self.is_gone(): self.save_to_disk() def resume(self): self.status = Status.QUEUED if self.encrypted > 0: # If user resumes after encryption warning, no more auto-pauses self.encrypted = 2 if self.rating_filtered: # If user resumes after filtered warning, no more auto-pauses self.rating_filtered = 2 # If user resumes after warning, reset duplicate/oversized/incomplete/unwanted indicators self.duplicate = False self.oversized = False self.incomplete = False if self.unwanted_ext: # If user resumes after "unwanted" warning, no more auto-pauses self.unwanted_ext = 2 @synchronized(NZO_LOCK) def add_parfile(self, parfile): """ Add parfile to the files to be downloaded Resets trylist just to be sure Adjust download-size accordingly """ if not parfile.completed and parfile not in self.files and parfile not in self.finished_files: parfile.reset_all_try_lists() self.files.append(parfile) self.bytes_tried -= parfile.bytes_left @synchronized(NZO_LOCK) def remove_parset(self, setname): if setname in self.extrapars: self.extrapars.pop(setname) if setname in self.partable: self.partable.pop(setname) @synchronized(NZO_LOCK) def remove_extrapar(self, parfile): """ Remove par file from any/all sets """ for _set in self.extrapars: if parfile in self.extrapars[_set]: self.extrapars[_set].remove(parfile) @synchronized(NZO_LOCK) def prospective_add(self, nzf): """ Add par2 files to compensate for missing articles This fails in case of multi-sets with identical setnames """ # Make sure to also select a parset if it was in the original filename original_filename = self.renames.get(nzf.filename, '') # Get some blocks! if not nzf.is_par2: # We have to find the right par-set blocks_new = 0 for parset in self.extrapars.keys(): if (parset in nzf.filename or parset in original_filename) and self.extrapars[parset]: for new_nzf in self.extrapars[parset]: self.add_parfile(new_nzf) blocks_new += int_conv(new_nzf.blocks) # Enough now? if blocks_new >= self.bad_articles: logging.info('Prospectively added %s repair blocks to %s', blocks_new, self.final_name) break # Reset NZO TryList self.reset_try_list() def add_to_direct_unpacker(self, nzf): """ Start or add to DirectUnpacker """ if not self.direct_unpacker: sabnzbd.directunpacker.DirectUnpacker(self) self.direct_unpacker.add(nzf) def abort_direct_unpacker(self): """ Abort any running DirectUnpackers """ if self.direct_unpacker: self.direct_unpacker.abort() def check_quality(self, req_ratio=0): """ Determine amount of articles present on servers and return (gross available, nett) bytes """ # Few missing articles in RAR-only job might still work if self.bad_articles <= MAX_BAD_ARTICLES: logging.debug('Download Quality: bad-articles=%s', self.bad_articles) return True, 200 # Do the full check need = 0L pars = 0L short = 0L anypars = False for nzf_id in self.files_table: nzf = self.files_table[nzf_id] if nzf.deleted: short += nzf.bytes_left if RE_QUICK_PAR2_CHECK.search(nzf.subject): pars += nzf.bytes anypars = True else: need += nzf.bytes have = need + pars - short ratio = float(have) / float(max(1, need)) if anypars: enough = ratio * 100.0 >= (req_ratio or float(cfg.req_completion_rate())) else: enough = have >= need logging.debug('Download Quality: enough=%s, have=%s, need=%s, ratio=%s', enough, have, need, ratio) return enough, ratio @synchronized(NZO_LOCK) def set_download_report(self): if self.avg_bps_total and self.bytes_downloaded and self.avg_bps_freq: # get the deltatime since the download started avg_bps = self.avg_bps_total / self.avg_bps_freq timecompleted = datetime.timedelta(seconds=self.bytes_downloaded / (avg_bps * 1024)) seconds = timecompleted.seconds # find the total time including days totaltime = (timecompleted.days / 86400) + seconds self.nzo_info['download_time'] = totaltime # format the total time the download took, in days, hours, and minutes, or seconds. complete_time = format_time_string(seconds, timecompleted.days) msg1 = T('Downloaded in %s at an average of %sB/s') % (complete_time, to_units(avg_bps * 1024)) msg1 += u'
' + T('Age') + ': ' + calc_age(self.avg_date, True) bad = self.nzo_info.get('bad_articles', 0) miss = self.nzo_info.get('missing_articles', 0) killed = self.nzo_info.get('killed_articles', 0) dups = self.nzo_info.get('duplicate_articles', 0) msg2 = msg3 = msg4 = msg5 = '' if bad: msg2 = (u'
' + T('%s articles were malformed')) % bad if miss: msg3 = (u'
' + T('%s articles were missing')) % miss if dups: msg4 = (u'
' + T('%s articles had non-matching duplicates')) % dups if killed: msg5 = (u'
' + T('%s articles were removed')) % killed msg = u''.join((msg1, msg2, msg3, msg4, msg5, )) self.set_unpack_info('Download', msg, unique=True) if self.url: self.set_unpack_info('Source', self.url, unique=True) if len(self.servercount) > 0: # Sort the servers first servers = config.get_servers() server_names = sorted(servers.keys(), key=lambda svr: '%d%02d%s' % (int(not servers[svr].enable()), servers[svr].priority(), servers[svr].displayname().lower())) msgs = ['%s=%sB' % (servers[server_name].displayname(), to_units(self.servercount[server_name])) for server_name in server_names if server_name in self.servercount] self.set_unpack_info('Servers', ', '.join(msgs), unique=True) @synchronized(NZO_LOCK) def increase_bad_articles_counter(self, type): """ Record information about bad articles """ if type not in self.nzo_info: self.nzo_info[type] = 0 self.nzo_info[type] += 1 self.bad_articles += 1 def get_article(self, server, servers): article = None nzf_remove_list = [] # Did we go through all first-articles? if self.first_articles: for article_test in self.first_articles: article = article_test.get_article(server, servers) if article: break # Move on to next ones if not article: for nzf in self.files: if nzf.deleted: logging.debug('Skipping existing file %s', nzf.filename or nzf.subject) else: # Don't try to get an article if server is in try_list of nzf if not nzf.server_in_try_list(server): if not nzf.import_finished: # Only load NZF when it's a primary server # or when it's a backup server without active primaries if sabnzbd.highest_server(server): nzf.finish_import() # Still not finished? Something went wrong... if not nzf.import_finished and not self.is_gone(): logging.error(T('Error importing %s'), nzf) nzf_remove_list.append(nzf) nzf.nzo.status = Status.PAUSED continue else: continue article = nzf.get_article(server, servers) if article: break # Remove all files for which admin could not be read for nzf in nzf_remove_list: nzf.deleted = True self.files.remove(nzf) # If cleanup emptied the active files list, end this job if nzf_remove_list and not self.files: sabnzbd.NzbQueue.do.end_job(self) if not article: # No articles for this server, block for next time self.add_to_try_list(server) return article @synchronized(NZO_LOCK) def move_top_bulk(self, nzf_ids): self.cleanup_nzf_ids(nzf_ids) if nzf_ids: target = range(len(nzf_ids)) while 1: self.move_up_bulk(nzf_ids, cleanup=False) pos_nzf_table = self.build_pos_nzf_table(nzf_ids) keys = pos_nzf_table.keys() keys.sort() if target == keys: break @synchronized(NZO_LOCK) def move_bottom_bulk(self, nzf_ids): self.cleanup_nzf_ids(nzf_ids) if nzf_ids: target = range(len(self.files) - len(nzf_ids), len(self.files)) while 1: self.move_down_bulk(nzf_ids, cleanup=False) pos_nzf_table = self.build_pos_nzf_table(nzf_ids) keys = pos_nzf_table.keys() keys.sort() if target == keys: break @synchronized(NZO_LOCK) def move_up_bulk(self, nzf_ids, cleanup=True): if cleanup: self.cleanup_nzf_ids(nzf_ids) if nzf_ids: pos_nzf_table = self.build_pos_nzf_table(nzf_ids) while pos_nzf_table: pos = min(pos_nzf_table) nzf = pos_nzf_table.pop(pos) if pos > 0: tmp_nzf = self.files[pos - 1] if tmp_nzf.nzf_id not in nzf_ids: self.files[pos - 1] = nzf self.files[pos] = tmp_nzf @synchronized(NZO_LOCK) def move_down_bulk(self, nzf_ids, cleanup=True): if cleanup: self.cleanup_nzf_ids(nzf_ids) if nzf_ids: pos_nzf_table = self.build_pos_nzf_table(nzf_ids) while pos_nzf_table: pos = max(pos_nzf_table) nzf = pos_nzf_table.pop(pos) if pos < len(self.files) - 1: tmp_nzf = self.files[pos + 1] if tmp_nzf.nzf_id not in nzf_ids: self.files[pos + 1] = nzf self.files[pos] = tmp_nzf def verify_nzf_filename(self, nzf, yenc_filename=None): """ Get filename from par2-info or from yenc """ # Already done? if nzf.filename_checked: return # If we have the md5, use it to rename if nzf.md5of16k and self.md5of16k: # Don't check again, even if no match nzf.filename_checked = True # Find the match and rename if nzf.md5of16k in self.md5of16k: new_filename = platform_encode(self.md5of16k[nzf.md5of16k]) # Was it even new? if new_filename != nzf.filename: logging.info('Detected filename based on par2: %s -> %s', nzf.filename, new_filename) self.renamed_file(new_filename, nzf.filename) nzf.filename = new_filename return # Fallback to yenc/nzb name (also when there is no partnum=1) # We also keep the NZB name in case it ends with ".par2" (usually correct) if yenc_filename and yenc_filename != nzf.filename and not is_obfuscated_filename(yenc_filename) and not nzf.filename.endswith('.par2'): logging.info('Detected filename from yenc: %s -> %s', nzf.filename, yenc_filename) self.renamed_file(yenc_filename, nzf.filename) nzf.filename = yenc_filename def verify_all_filenames_and_resort(self): """ Verify all filenames based on par2 info and then re-sort files """ logging.info('Checking all filenames for %s', self.final_name) for nzf_verify in self.files: self.verify_nzf_filename(nzf_verify) logging.info('Re-sorting %s after getting filename information', self.final_name) self.sort_nzfs() @synchronized(NZO_LOCK) def renamed_file(self, name_set, old_name=None): """ Save renames at various stages (Download/PP) to be used on Retry. Accepts strings and dicts. """ if not old_name: # Add to dict self.renames.update(name_set) else: self.renames[name_set] = old_name # Determine if rating information (including site identifier so rating can be updated) # is present in metadata and if so store it @synchronized(NZO_LOCK) def update_rating(self): if cfg.rating_enable(): try: def _get_first_meta(type): values = self.nzo_info.get('x-oznzb-rating-' + type, None) or self.nzo_info.get('x-rating-' + type, None) return values[0] if values and isinstance(values, list) else values rating_types = ['url', 'host', 'video', 'videocnt', 'audio', 'audiocnt', 'voteup', 'votedown', 'spam', 'confirmed-spam', 'passworded', 'confirmed-passworded'] fields = {} for k in rating_types: fields[k] = _get_first_meta(k) Rating.do.add_rating(_get_first_meta('id'), self.nzo_id, fields) except: pass ## end nzo.Mutators ####################################################### ########################################################################### @property def workpath(self): """ Return the full path for my job-admin folder """ return long_path(get_admin_path(self.work_name, self.futuretype)) @property def downpath(self): """ Return the full path for my download folder """ if self.futuretype: return '' else: return long_path(os.path.join(cfg.download_dir.get_path(), self.work_name)) @property def group(self): if self.groups: return self.groups[0] else: return None @property def remaining(self): """ Return remaining bytes """ return self.bytes - self.bytes_tried @synchronized(NZO_LOCK) def purge_data(self, keep_basic=False, del_files=False): """ Remove all admin info, 'keep_basic' preserves attribs and nzb """ logging.info('[%s] Purging data for job %s (keep_basic=%s, del_files=%s)', caller_name(), self.final_name, keep_basic, del_files) wpath = self.workpath for nzf in self.files: sabnzbd.remove_data(nzf.nzf_id, wpath) for _set in self.extrapars: for nzf in self.extrapars[_set]: sabnzbd.remove_data(nzf.nzf_id, wpath) for nzf in self.finished_files: sabnzbd.remove_data(nzf.nzf_id, wpath) if not self.futuretype: if keep_basic: remove_all(wpath, 'SABnzbd_nz?_*', keep_folder=True) remove_all(wpath, 'SABnzbd_article_*', keep_folder=True) # We save the renames file sabnzbd.save_data(self.renames, RENAMES_FILE, self.workpath, silent=True) else: remove_all(wpath, recursive=True) if del_files: remove_all(self.downpath, recursive=True) else: try: remove_dir(self.downpath) except: logging.debug('Folder not removed: %s', self.downpath) pass def gather_info(self, full=False): queued_files = [] if full: # extrapars can change during iteration with NZO_LOCK: for _set in self.extrapars: for nzf in self.extrapars[_set]: # Don't show files twice if not nzf.completed and nzf not in self.files: queued_files.append(nzf) return PNFO(self.repair, self.unpack, self.delete, self.script, self.nzo_id, self.final_name_labeled, self.password, {}, '', self.cat, self.url, self.remaining, self.bytes, self.avg_stamp, self.avg_date, self.finished_files if full else [], self.files if full else [], queued_files, self.status, self.priority, self.bytes_missing, self.direct_unpacker.get_formatted_stats() if self.direct_unpacker else 0) def get_nzf_by_id(self, nzf_id): if nzf_id in self.files_table: return self.files_table[nzf_id] @synchronized(NZO_LOCK) def set_unpack_info(self, key, msg, unique=False): """ Builds a dictionary containing the stage name (key) and a message If unique is present, it will only have a single line message """ # Unique messages allow only one line per stage(key) if not unique: if key not in self.unpack_info: self.unpack_info[key] = [] self.unpack_info[key].append(msg) else: self.unpack_info[key] = [msg] def set_action_line(self, action=None, msg=None): if action and msg: self.action_line = '%s: %s' % (action, msg) else: self.action_line = '' # Make sure it's updated in the interface sabnzbd.history_updated() @property def repair_opts(self): return self.repair, self.unpack, self.delete @synchronized(NZO_LOCK) def save_to_disk(self): """ Save job's admin to disk """ self.save_attribs() if self.nzo_id and not self.is_gone(): sabnzbd.save_data(self, self.nzo_id, self.workpath) def save_attribs(self): set_attrib_file(self.workpath, (self.cat, self.pp, self.script, self.priority, self.final_name, self.password, self.url)) @synchronized(NZO_LOCK) def build_pos_nzf_table(self, nzf_ids): pos_nzf_table = {} for nzf_id in nzf_ids: if nzf_id in self.files_table: nzf = self.files_table[nzf_id] pos = self.files.index(nzf) pos_nzf_table[pos] = nzf return pos_nzf_table @synchronized(NZO_LOCK) def cleanup_nzf_ids(self, nzf_ids): for nzf_id in nzf_ids[:]: if nzf_id in self.files_table: if self.files_table[nzf_id] not in self.files: nzf_ids.remove(nzf_id) else: nzf_ids.remove(nzf_id) def has_duplicates(self): """ Return (res, series) where "res" is True when this is a duplicate where "series" is True when this is an episode """ no_dupes = cfg.no_dupes() no_series_dupes = cfg.no_series_dupes() series_propercheck = cfg.series_propercheck() # abort logic if dupe check is off for both nzb+series if not no_dupes and not no_series_dupes: return False, False series = False res = False history_db = HistoryDB() # dupe check off nzb contents if no_dupes: res = history_db.have_md5sum(self.md5sum) logging.debug('Dupe checking NZB in history: filename=%s, md5sum=%s, result=%s', self.filename, self.md5sum, res) if not res and cfg.backup_for_duplicates(): res = sabnzbd.backup_exists(self.filename) logging.debug('Dupe checking NZB against backup: filename=%s, result=%s', self.filename, res) # dupe check off nzb filename if not res and no_series_dupes: series, season, episode, misc = sabnzbd.newsunpack.analyse_show(self.final_name) if RE_PROPER.match(misc) and series_propercheck: logging.debug('Dupe checking series+season+ep in history aborted due to PROPER/REAL/REPACK found') else: res = history_db.have_episode(series, season, episode) logging.debug('Dupe checking series+season+ep in history: series=%s, season=%s, episode=%s, result=%s', series, season, episode, res) history_db.close() return res, series def is_gone(self): """ Is this job still going somehow? """ return self.status in (Status.COMPLETED, Status.DELETED, Status.FAILED) def __getstate__(self): """ Save to pickle file, selecting attributes """ dict_ = {} for item in NzbObjectSaver: dict_[item] = getattr(self, item) dict_['try_list'] = TryList.__getstate__(self) return dict_ def __setstate__(self, dict_): """ Load from pickle file, selecting attributes """ for item in NzbObjectSaver: try: setattr(self, item, dict_[item]) except KeyError: # Handle new attributes setattr(self, item, None) TryList.__setstate__(self, dict_.get('try_list', [])) # Set non-transferable values self.pp_active = False self.avg_stamp = time.mktime(self.avg_date.timetuple()) self.url_wait = None self.url_tries = 0 self.to_be_removed = False self.direct_unpacker = None if self.meta is None: self.meta = {} if self.servercount is None: self.servercount = {} if self.md5of16k is None: self.md5of16k = {} if self.renames is None: self.renames = {} if self.bad_articles is None: self.bad_articles = 0 if self.bytes_missing is None: self.bytes_missing = 0 if self.bytes_tried is None: # Fill with old info self.bytes_tried = 0 for nzf in self.finished_files: # Emulate behavior of 1.0.x self.bytes_tried += nzf.bytes for nzf in self.files: self.bytes_tried += nzf.bytes - nzf.bytes_left def __repr__(self): return "" % self.filename def nzf_get_filename(nzf): """ Return filename, if the filename not set, try the the full subject line instead. Can produce non-ideal results """ name = nzf.filename if not name: name = nzf.subject if not name: name = '' return name.lower() def nzf_cmp_date(nzf1, nzf2): """ Compare files based on date, but give vol-par files preference. Wrapper needed, because `cmp` function doesn't handle extra parms. """ return nzf_cmp_name(nzf1, nzf2, name=False) def nzf_cmp_name(nzf1, nzf2, name=True): # The comparison will sort .par2 files to the top of the queue followed by .rar files, # they will then be sorted by name. name1 = nzf_get_filename(nzf1) name2 = nzf_get_filename(nzf2) # Determine vol-pars is_par1 = '.vol' in name1 and '.par2' in name1 is_par2 = '.vol' in name2 and '.par2' in name2 # mini-par2 in front if not is_par1 and name1.endswith('.par2'): return -1 if not is_par2 and name2.endswith('.par2'): return 1 # vol-pars go to the back if is_par1 and not is_par2: return 1 if is_par2 and not is_par1: return -1 if name: # Prioritize .rar files above any other type of file (other than vol-par) m1 = RE_RAR.search(name1) m2 = RE_RAR.search(name2) if m1 and not (is_par2 or m2): return -1 elif m2 and not (is_par1 or m1): return 1 # Force .rar to come before 'r00' if m1 and m1.group(1) == '.rar': name1 = name1.replace('.rar', '.r//') if m2 and m2.group(1) == '.rar': name2 = name2.replace('.rar', '.r//') return cmp(name1, name2) else: # Do date comparison return cmp(nzf1.date, nzf2.date) def create_work_name(name): """ Remove ".nzb" and ".par(2)" """ strip_ext = ['.nzb', '.par', '.par2'] name = name.strip() if name.find('://') < 0: name_base, ext = os.path.splitext(name) # In case it was one of these, there might be more while ext.lower() in strip_ext: name = name_base name_base, ext = os.path.splitext(name) return name.strip() else: return name.strip() def scan_password(name): """ Get password (if any) from the title """ if 'http://' in name or 'https://' in name: return name, None braces = name.find('{{') if braces < 0: braces = len(name) slash = name.find('/') # Look for name/password, but make sure that '/' comes before any {{ if slash >= 0 and slash < braces and 'password=' not in name: # Is it maybe in 'name / password' notation? if slash == name.find(' / ') + 1: # Remove the extra space after name and before password return name[:slash - 1].strip('. '), name[slash + 2:] return name[:slash].strip('. '), name[slash + 1:] # Look for "name password=password" pw = name.find('password=') if pw >= 0: return name[:pw].strip('. '), name[pw + 9:] # Look for name{{password}} if braces < len(name) and name.endswith('}}'): return name[:braces].strip('. '), name[braces + 2:len(name) - 2] # Look again for name/password if slash >= 0: return name[:slash].strip('. '), name[slash + 1:] # No password found return name, None def get_attrib_file(path, size): """ Read job's attributes from file """ attribs = [] path = os.path.join(path, ATTRIB_FILE) try: f = open(path, 'r') except: return [None for unused in xrange(size)] for unused in xrange(size): line = f.readline().strip('\r\n ') if line: if line.lower() == 'none': line = None try: line = int(line) except: pass attribs.append(line) else: attribs.append(None) f.close() return attribs def set_attrib_file(path, attribs): """ Write job's attributes to file """ path = os.path.join(path, ATTRIB_FILE) try: f = open(path, 'w') except: return for item in attribs: f.write('%s\n' % item) f.close() def name_extractor(subject): """ Try to extract a file name from a subject line, return `subject` if in doubt """ result = subject for name in re.findall(SUBJECT_FN_MATCHER, subject): name = name.strip(' "') if name and RE_NORMAL_NAME.search(name): result = name return platform_encode(result) def matcher(pattern, txt): """ Return True if `pattern` is sufficiently equal to `txt` """ if txt.endswith(pattern): txt = txt[:txt.rfind(pattern)].strip() return (not txt) or txt.endswith('"') else: return False SABnzbd-2.3.2/sabnzbd/osxmenu.py0000644000000000000000000007677513217005257014652 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.osxmenu - OSX Top Menu """ import objc from Foundation import * from AppKit import * from PyObjCTools import AppHelper from objc import YES, NO import os import cherrypy import sys import time import logging import sabnzbd import sabnzbd.cfg from sabnzbd.constants import VALID_ARCHIVES, MEBI, Status from sabnzbd.misc import get_filename, get_ext, diskspace, to_units from sabnzbd.panic import launch_a_browser import sabnzbd.notifier as notifier from sabnzbd.api import fast_queue from sabnzbd.nzbqueue import NzbQueue import sabnzbd.config as config import sabnzbd.scheduler as scheduler import sabnzbd.downloader import sabnzbd.dirscanner as dirscanner from sabnzbd.bpsmeter import BPSMeter from sabnzbd.encoding import unicoder status_icons = {'idle': '../Resources/sab_idle.tiff', 'pause': '../Resources/sab_pause.tiff', 'clicked': '../Resources/sab_clicked.tiff'} start_time = NSDate.date() debug = 0 class SABnzbdDelegate(NSObject): icons = {} status_bar = None osx_icon = True history_db = None isLeopard = 0 def awakeFromNib(self): # Status Bar initialize if debug == 1: NSLog("[osx] awake") self.buildMenu() # Timer for updating menu self.timer = NSTimer.alloc().initWithFireDate_interval_target_selector_userInfo_repeats_(start_time, 3.0, self, 'updateAction:', None, True) NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer, NSDefaultRunLoopMode) NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer, NSEventTrackingRunLoopMode) # NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer, NSModalPanelRunLoopMode) self.timer.fire() def buildMenu(self): # logging.info("building menu") status_bar = NSStatusBar.systemStatusBar() self.status_item = status_bar.statusItemWithLength_(NSVariableStatusItemLength) for i in status_icons.keys(): self.icons[i] = NSImage.alloc().initByReferencingFile_(status_icons[i]) if sabnzbd.DARWIN_VERSION > 9: # Support for Yosemite Dark Mode self.icons[i].setTemplate_(YES) self.status_item.setImage_(self.icons['idle']) self.status_item.setAlternateImage_(self.icons['clicked']) self.status_item.setHighlightMode_(1) self.status_item.setToolTip_('SABnzbd') self.status_item.setEnabled_(YES) if debug == 1: NSLog("[osx] menu 1 building") # Wait for SABnzbd Initialization # cherrypy.engine.wait(cherrypy.process.wspbus.states.STARTED) # Wait for translated texts to be loaded while not sabnzbd.WEBUI_READY and not sabnzbd.SABSTOP: time.sleep(0.5) if debug == 1: NSLog("[osx] language file not loaded, waiting") # Variables self.state = "Idle" try: self.speed = sabnzbd.downloader.Downloader.do.get_limit() except: self.speed = 0 self.version_notify = 1 self.status_removed = 0 if debug == 1: NSLog("[osx] menu 2 initialization") # Menu construction self.menu = NSMenu.alloc().init() try: menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Dummy", '', '') menu_item.setHidden_(YES) self.isLeopard = 1 except: self.isLeopard = 0 if debug == 1: NSLog("[osx] menu 3 construction") # Warnings Item self.warnings_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Warnings'), 'openBrowserAction:', '') if self.isLeopard: self.warnings_menu_item.setHidden_(YES) else: self.warnings_menu_item.setEnabled_(NO) self.warnings_menu_item.setRepresentedObject_("connections/") self.menu.addItem_(self.warnings_menu_item) if debug == 1: NSLog("[osx] menu 4 warning added") # State Item self.state_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Idle'), 'openBrowserAction:', '') self.state_menu_item.setRepresentedObject_("") self.menu.addItem_(self.state_menu_item) if debug == 1: NSLog("[osx] menu 5 state added") # Config Item menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Configuration'), 'openBrowserAction:', '') menu_item.setRepresentedObject_("config/general/") menu_item.setAlternate_(YES) menu_item.setKeyEquivalentModifierMask_(NSAlternateKeyMask) self.menu.addItem_(menu_item) if debug == 1: NSLog("[osx] menu 6 config added") # Queue Item self.queue_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Queue'), 'openBrowserAction:', '') self.queue_menu_item.setRepresentedObject_("") self.menu.addItem_(self.queue_menu_item) if debug == 1: NSLog("[osx] menu 7 queue added") # Purge Queue Item self.purgequeue_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Purge Queue'), 'purgeAction:', '') self.purgequeue_menu_item.setRepresentedObject_("queue") self.purgequeue_menu_item.setAlternate_(YES) self.purgequeue_menu_item.setKeyEquivalentModifierMask_(NSAlternateKeyMask) self.menu.addItem_(self.purgequeue_menu_item) if debug == 1: NSLog("[osx] menu 8 purge queue added") # History Item self.history_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('History'), 'openBrowserAction:', '') self.history_menu_item.setRepresentedObject_("") self.menu.addItem_(self.history_menu_item) if debug == 1: NSLog("[osx] menu 9 history added") # Purge History Item self.purgehistory_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Purge History'), 'purgeAction:', '') self.purgehistory_menu_item.setRepresentedObject_("history") self.purgehistory_menu_item.setAlternate_(YES) self.purgehistory_menu_item.setKeyEquivalentModifierMask_(NSAlternateKeyMask) self.menu.addItem_(self.purgehistory_menu_item) if debug == 1: NSLog("[osx] menu 10 purge history added") self.separator_menu_item = NSMenuItem.separatorItem() self.menu.addItem_(self.separator_menu_item) # Limit Speed Item & Submenu self.speed_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Limit Speed'), '', '') self.menu_speed = NSMenu.alloc().init() speeds = {10: '10%', 20: '20%', 30: '30%', 40: '40%', 50: '50%', 60: '60%', 70: '70%', 80: '80%', 90: '90%', 100: '100%' } for speed in sorted(speeds.keys()): menu_speed_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('%s' % (speeds[speed]), 'speedlimitAction:', '') menu_speed_item.setRepresentedObject_("%s" % (speed)) self.menu_speed.addItem_(menu_speed_item) self.speed_menu_item.setSubmenu_(self.menu_speed) self.menu.addItem_(self.speed_menu_item) if debug == 1: NSLog("[osx] menu 11 limit speed added") # Pause Item & Submenu self.pause_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Pause'), 'pauseAction:', '') self.pause_menu_item.setRepresentedObject_('0') self.menu_pause = NSMenu.alloc().init() for i in range(6): menu_pause_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("%s %s" % ((i + 1) * 10, T('min.')), 'pauseAction:', '') menu_pause_item.setRepresentedObject_("%s" % ((i + 1) * 10)) self.menu_pause.addItem_(menu_pause_item) self.pause_menu_item.setSubmenu_(self.menu_pause) self.menu.addItem_(self.pause_menu_item) if debug == 1: NSLog("[osx] menu 12 pause added") # Resume Item self.resume_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Resume'), 'resumeAction:', '') if self.isLeopard: self.resume_menu_item.setHidden_(YES) else: self.resume_menu_item.setEnabled_(NO) self.menu.addItem_(self.resume_menu_item) if debug == 1: NSLog("[osx] menu 13 resume added") # Watched folder Item self.watched_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Scan watched folder'), 'watchedFolderAction:', '') if self.isLeopard: self.watched_menu_item.setHidden_(YES) else: self.watched_menu_item.setEnabled_(NO) self.menu.addItem_(self.watched_menu_item) # All RSS feeds self.rss_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Read all RSS feeds'), 'rssAction:', '') if self.isLeopard: self.rss_menu_item.setHidden_(YES) else: self.rss_menu_item.setEnabled_(NO) self.menu.addItem_(self.rss_menu_item) self.separator2_menu_item = NSMenuItem.separatorItem() self.menu.addItem_(self.separator2_menu_item) if debug == 1: NSLog("[osx] menu 14 watched folder added") # Complete Folder Item self.completefolder_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Complete Folder') + '\t\t\t', 'openFolderAction:', '') self.completefolder_menu_item.setRepresentedObject_(sabnzbd.cfg.complete_dir.get_path()) self.menu.addItem_(self.completefolder_menu_item) # Incomplete Folder Item self.incompletefolder_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Incomplete Folder') + '\t\t', 'openFolderAction:', '') self.incompletefolder_menu_item.setRepresentedObject_(sabnzbd.cfg.download_dir.get_path()) self.menu.addItem_(self.incompletefolder_menu_item) if debug == 1: NSLog("[osx] menu 15 folder added") self.menu.addItem_(NSMenuItem.separatorItem()) # Set diagnostic menu self.diagnostic_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Troubleshoot'), '', '') self.menu_diagnostic = NSMenu.alloc().init() diag_items = ((T('Restart'), 'restartAction:'), (T('Restart') + ' - 127.0.0.1:8080', 'restartSafeHost:'), (T('Restart without login'), 'restartNoLogin:') ) for item in diag_items: menu_diag_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(item[0], item[1], '') menu_diag_item.setRepresentedObject_(item[0]) self.menu_diagnostic.addItem_(menu_diag_item) self.diagnostic_menu_item.setSubmenu_(self.menu_diagnostic) self.menu.addItem_(self.diagnostic_menu_item) if debug == 1: NSLog("[osx] menu 16 Diagnostic added") # Quit Item menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Quit'), 'terminate:', '') self.menu.addItem_(menu_item) if debug == 1: NSLog("[osx] menu 16 quit added") # Add menu to Status Item self.status_item.setMenu_(self.menu) if debug == 1: NSLog("[osx] menu 18 menu added") def updateAction_(self, notification): try: self.osx_icon = sabnzbd.cfg.osx_menu() if self.osx_icon: if self.status_removed == 1: self.buildMenu() if self.serverUpdate(): self.warningsUpdate() self.queueUpdate() self.historyUpdate() self.stateUpdate() self.iconUpdate() self.pauseUpdate() self.speedlimitUpdate() self.versionUpdate() self.diskspaceUpdate() self.watchedUpdate() self.rssUpdate() else: if self.status_removed == 0: status_bar = NSStatusBar.systemStatusBar() status_bar.removeStatusItem_(self.status_item) self.status_removed = 1 status_bar = None self.status_item = None except: logging.info("[osx] Exception %s" % (sys.exc_info()[0])) def queueUpdate(self): try: qnfo = NzbQueue.do.queue_info(start=0, limit=10) pnfo_list = qnfo.list bytesleftprogess = 0 bpsnow = BPSMeter.do.get_bps() self.info = "" self.menu_queue = NSMenu.alloc().init() if len(pnfo_list): menu_queue_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Queue First 10 Items'), '', '') self.menu_queue.addItem_(menu_queue_item) self.menu_queue.addItem_(NSMenuItem.separatorItem()) for pnfo in pnfo_list: filename = unicoder(pnfo.filename) bytesleft = pnfo.bytes_left / MEBI bytesleftprogess += pnfo.bytes_left bytes = pnfo.bytes / MEBI nzo_id = pnfo.nzo_id timeleft = self.calc_timeleft_(bytesleftprogess, bpsnow) job = "%s\t(%d/%d MB) %s" % (filename, bytesleft, bytes, timeleft) menu_queue_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(job, '', '') self.menu_queue.addItem_(menu_queue_item) self.info = "%d nzb(s)\t( %d / %d MB )" % (qnfo.q_size_list, (qnfo.bytes_left / MEBI), (qnfo.bytes / MEBI)) else: menu_queue_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Empty'), '', '') self.menu_queue.addItem_(menu_queue_item) self.queue_menu_item.setSubmenu_(self.menu_queue) except: logging.info("[osx] queueUpdate Exception %s" % (sys.exc_info()[0])) def historyUpdate(self): try: # Fetch history items if not self.history_db: self.history_db = sabnzbd.database.HistoryDB() items, fetched_items, _total_items = self.history_db.fetch_history(0, 10, None) self.menu_history = NSMenu.alloc().init() self.failedAttributes = {NSForegroundColorAttributeName: NSColor.redColor(), NSFontAttributeName: NSFont.menuFontOfSize_(14.0)} menu_history_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('History Last 10 Items'), '', '') self.menu_history.addItem_(menu_history_item) self.menu_history.addItem_(NSMenuItem.separatorItem()) if fetched_items: for history in items: # logging.info("[osx] history : %s" % (history)) job = "%s" % (history['name']) path = "" if os.path.isdir(history['storage']) or os.path.isfile(history['storage']): if os.path.isfile(history['storage']): path = os.path.dirname(history['storage']) else: path = history['storage'] if path: menu_history_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(job, 'openFolderAction:', '') else: menu_history_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(job, '', '') if history['status'] != Status.COMPLETED: jobfailed = NSAttributedString.alloc().initWithString_attributes_(job, self.failedAttributes) menu_history_item.setAttributedTitle_(jobfailed) menu_history_item.setRepresentedObject_("%s" % (path)) self.menu_history.addItem_(menu_history_item) else: menu_history_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Empty'), '', '') self.menu_history.addItem_(menu_history_item) self.history_menu_item.setSubmenu_(self.menu_history) except: logging.info("[osx] historyUpdate Exception %s" % (sys.exc_info()[0])) def warningsUpdate(self): try: warnings = sabnzbd.GUIHANDLER.count() if warnings: warningsAttributes = { NSForegroundColorAttributeName: NSColor.redColor(), NSFontAttributeName: NSFont.menuFontOfSize_(14.0) } warningsTitle = NSAttributedString.alloc().initWithString_attributes_("%s : %s" % (T('Warnings'), warnings), warningsAttributes) self.warnings_menu_item.setAttributedTitle_(warningsTitle) if self.isLeopard: self.warnings_menu_item.setHidden_(NO) else: self.warnings_menu_item.setEnabled_(YES) else: self.warnings_menu_item.setTitle_("%s : 0" % (T('Warnings'))) if self.isLeopard: self.warnings_menu_item.setHidden_(YES) else: self.warnings_menu_item.setEnabled_(NO) except: logging.info("[osx] warningsUpdate Exception %s" % (sys.exc_info()[0])) def stateUpdate(self): try: paused, bytes_left, bpsnow, time_left = fast_queue() if paused: self.state = T('Paused') if sabnzbd.scheduler.pause_int() != "0": self.setMenuTitle_("\n\n%s\n" % (sabnzbd.scheduler.pause_int())) else: self.setMenuTitle_("") elif bytes_left > 0: self.state = "" speed = to_units(bpsnow) # "10.1 MB/s" doesn't fit, remove space char if 'M' in speed and len(speed) > 5: speed = speed.replace(' ', '') time_left = (bpsnow > 10 and time_left) or "------" statusbarText = "\n\n%s\n%sB/s\n" % (time_left, speed) if sabnzbd.SABSTOP: statusbarText = "..." if not sabnzbd.cfg.osx_speed(): statusbarText = "" self.setMenuTitle_(statusbarText) else: self.state = T('Idle') self.setMenuTitle_("") if self.state != "" and self.info != "": self.state_menu_item.setTitle_("%s - %s" % (self.state, self.info)) if self.info == "": self.state_menu_item.setTitle_("%s" % (self.state)) else: self.state_menu_item.setTitle_("%s" % (self.info)) except: logging.info("[osx] stateUpdate Exception %s" % (sys.exc_info()[0])) def iconUpdate(self): try: if sabnzbd.downloader.Downloader.do.paused: self.status_item.setImage_(self.icons['pause']) else: self.status_item.setImage_(self.icons['idle']) except: logging.info("[osx] iconUpdate Exception %s" % (sys.exc_info()[0])) def pauseUpdate(self): try: if sabnzbd.downloader.Downloader.do.paused: if self.isLeopard: self.resume_menu_item.setHidden_(NO) self.pause_menu_item.setHidden_(YES) else: self.resume_menu_item.setEnabled_(YES) self.pause_menu_item.setEnabled_(NO) else: if self.isLeopard: self.resume_menu_item.setHidden_(YES) self.pause_menu_item.setHidden_(NO) else: self.resume_menu_item.setEnabled_(NO) self.pause_menu_item.setEnabled_(YES) except: logging.info("[osx] pauseUpdate Exception %s" % (sys.exc_info()[0])) def speedlimitUpdate(self): try: speed = int(sabnzbd.downloader.Downloader.do.get_limit()) if self.speed != speed: self.speed = speed speedsValues = self.menu_speed.numberOfItems() for i in range(speedsValues): menuitem = self.menu_speed.itemAtIndex_(i) if speed == int(menuitem.representedObject()): menuitem.setState_(NSOnState) else: menuitem.setState_(NSOffState) except: logging.info("[osx] speedlimitUpdate Exception %s" % (sys.exc_info()[0])) def versionUpdate(self): try: if sabnzbd.NEW_VERSION and self.version_notify: # logging.info("[osx] New Version : %s" % (sabnzbd.NEW_VERSION)) new_release, _new_rel_url = sabnzbd.NEW_VERSION notifier.send_notification("SABnzbd", "%s : %s" % (T('New release available'), new_release), 'other') self.version_notify = 0 except: logging.info("[osx] versionUpdate Exception %s" % (sys.exc_info()[0])) def watchedUpdate(self): try: if sabnzbd.cfg.dirscan_dir(): if self.isLeopard: self.watched_menu_item.setHidden_(NO) else: self.watched_menu_item.setEnabled_(YES) else: if self.isLeopard: self.watched_menu_item.setHidden_(YES) else: self.watched_menu_item.setEnabled_(NO) except: logging.info("[osx] watchedUpdate Exception %s" % (sys.exc_info()[0])) def rssUpdate(self): try: if self.isLeopard: self.rss_menu_item.setHidden_(NO) else: self.rss_menu_item.setEnabled_(YES) except: logging.info("[osx] rssUpdate Exception %s" % (sys.exc_info()[0])) def serverUpdate(self): try: if not config.get_servers(): self.state_menu_item.setTitle_(T('Go to wizard')) hide = YES alternate = NO value = 0 else: hide = NO alternate = YES value = 1 if self.isLeopard: self.speed_menu_item.setHidden_(hide) self.resume_menu_item.setHidden_(hide) self.pause_menu_item.setHidden_(hide) self.watched_menu_item.setHidden_(hide) self.rss_menu_item.setHidden_(hide) self.purgequeue_menu_item.setAlternate_(alternate) self.purgequeue_menu_item.setHidden_(hide) self.queue_menu_item.setHidden_(hide) self.purgehistory_menu_item.setAlternate_(alternate) self.purgehistory_menu_item.setHidden_(hide) self.history_menu_item.setHidden_(hide) self.separator_menu_item.setHidden_(hide) self.separator2_menu_item.setHidden_(hide) self.completefolder_menu_item.setHidden_(hide) self.incompletefolder_menu_item.setHidden_(hide) else: self.speed_menu_item.setEnabled_(alternate) self.resume_menu_item.setEnabled_(alternate) self.pause_menu_item.setEnabled_(alternate) self.watched_menu_item.setEnabled_(alternate) self.rss_menu_item.setEnabled_(alternate) self.purgequeue_menu_item.setAlternate_(alternate) self.purgequeue_menu_item.setEnabled_(alternate) self.queue_menu_item.setEnabled_(alternate) self.purgehistory_menu_item.setAlternate_(alternate) self.purgehistory_menu_item.setEnabled_(alternate) self.history_menu_item.setEnabled_(alternate) self.separator_menu_item.setEnabled_(alternate) self.separator2_menu_item.setEnabled_(alternate) self.completefolder_menu_item.setEnabled_(alternate) self.incompletefolder_menu_item.setEnabled_(alternate) return value except: logging.info("[osx] configUpdate Exception %s" % (sys.exc_info()[0])) return 0 def diskspaceUpdate(self): try: self.completefolder_menu_item.setTitle_("%s%.2f GB" % (T('Complete Folder') + '\t\t\t', diskspace()['complete_dir'][1])) self.incompletefolder_menu_item.setTitle_("%s%.2f GB" % (T('Incomplete Folder') + '\t\t', diskspace()['download_dir'][1])) except: logging.info("[osx] diskspaceUpdate Exception %s" % (sys.exc_info()[0])) def setMenuTitle_(self, text): try: style = NSMutableParagraphStyle.new() style.setParagraphStyle_(NSParagraphStyle.defaultParagraphStyle()) style.setAlignment_(NSCenterTextAlignment) style.setLineSpacing_(0.0) style.setMaximumLineHeight_(9.0) style.setParagraphSpacing_(-3.0) # Trying to change color of title to white when menu is open TO FIX if self.menu.highlightedItem(): # logging.info("Menu Clicked") titleColor = NSColor.highlightColor() else: # logging.info("Menu Not Clicked") titleColor = NSColor.blackColor() titleAttributes = { NSBaselineOffsetAttributeName: 5.0, NSFontAttributeName: NSFont.menuFontOfSize_(9.0), NSParagraphStyleAttributeName: style #,NSForegroundColorAttributeName: titleColor } title = NSAttributedString.alloc().initWithString_attributes_(text, titleAttributes) self.status_item.setAttributedTitle_(title) except: logging.info("[osx] setMenuTitle Exception %s" % (sys.exc_info()[0])) def calc_timeleft_(self, bytesleft, bps): """ Calculate the time left in the format HH:MM:SS """ try: totalseconds = int(bytesleft / bps) minutes, seconds = divmod(totalseconds, 60) hours, minutes = divmod(minutes, 60) if minutes < 10: minutes = '0%s' % minutes if seconds < 10: seconds = '0%s' % seconds return '%s:%s:%s' % (hours, minutes, seconds) except: return '0:00:00' def openBrowserAction_(self, sender): if sender.representedObject: link = sender.representedObject() else: link = "" launch_a_browser(sabnzbd.BROWSER_URL, True) def speedlimitAction_(self, sender): # logging.info("[osx] speed limit to %s" % (sender.representedObject())) speed = int(sender.representedObject()) if speed != self.speed: sabnzbd.downloader.Downloader.do.limit_speed('%s%%' % speed) self.speedlimitUpdate() def purgeAction_(self, sender): mode = sender.representedObject() # logging.info("[osx] purge %s" % (mode)) if mode == "queue": NzbQueue.do.remove_all() elif mode == "history": if not self.history_db: self.history_db = sabnzbd.database.HistoryDB() self.history_db.remove_history() def pauseAction_(self, sender): minutes = int(sender.representedObject()) # logging.info("[osx] pause for %s" % (minutes)) if minutes: scheduler.plan_resume(minutes) else: sabnzbd.downloader.Downloader.do.pause() def resumeAction_(self, sender): scheduler.plan_resume(0) def watchedFolderAction_(self, sender): sabnzbd.dirscanner.dirscan() def rssAction_(self, sender): scheduler.force_rss() def openFolderAction_(self, sender): folder2open = sender.representedObject() if isinstance(folder2open, unicode): folder2open = folder2open.encode("utf-8") if debug == 1: NSLog("[osx] %@", folder2open) os.system('open "%s"' % folder2open) # def aboutAction_(self, sender): # app = NSApplication.sharedApplication() # app.orderFrontStandardAboutPanel_(nil) def restartAction_(self, sender): self.setMenuTitle_("\n\n%s\n" % (T('Stopping...'))) logging.info('Restart requested by tray') sabnzbd.trigger_restart() self.setMenuTitle_("\n\n%s\n" % (T('Stopping...'))) def restartSafeHost_(self, sender): sabnzbd.cfg.cherryhost.set('127.0.0.1') sabnzbd.cfg.cherryport.set('8080') sabnzbd.cfg.enable_https.set(False) sabnzbd.config.save_config() self.setMenuTitle_("\n\n%s\n" % (T('Stopping...'))) sabnzbd.trigger_restart() self.setMenuTitle_("\n\n%s\n" % (T('Stopping...'))) def restartNoLogin_(self, sender): sabnzbd.cfg.username.set('') sabnzbd.cfg.password.set('') sabnzbd.config.save_config() self.setMenuTitle_("\n\n%s\n" % (T('Stopping...'))) sabnzbd.trigger_restart() self.setMenuTitle_("\n\n%s\n" % (T('Stopping...'))) def application_openFiles_(self, nsapp, filenames): # logging.info('[osx] file open') # logging.info('[osx] file : %s' % (filenames)) for name in filenames: logging.info('[osx] receiving from OSX : %s', name) if os.path.exists(name): fn = get_filename(name) # logging.info('[osx] filename : %s' % (fn)) if fn: if get_ext(name) in VALID_ARCHIVES: # logging.info('[osx] archive') dirscanner.ProcessArchiveFile(fn, name, keep=True) elif get_ext(name) in ('.nzb', '.gz', '.bz2'): # logging.info('[osx] nzb') dirscanner.ProcessSingleFile(fn, name, keep=True) # logging.info('opening done') def applicationShouldTerminate_(self, sender): logging.info('[osx] application terminating') self.setMenuTitle_("\n\n%s\n" % (T('Stopping...'))) self.status_item.setHighlightMode_(NO) self.osx_icon = False logging.info('[osx] application stopping daemon') sabnzbd.halt() cherrypy.engine.exit() sabnzbd.SABSTOP = True try: notifier.send_notification('SABnzbd', T('SABnzbd shutdown finished'), notifier.NOTIFICATION['other']) except AttributeError: # Fails for the OSX binary pass logging.info('Leaving SABnzbd') sys.stderr.flush() sys.stdout.flush() return NSTerminateNow def notify(notificationName, message): """ Send a notification to the OS (OSX-only) """ if sabnzbd.FOUNDATION: pool = Foundation.NSAutoreleasePool.alloc().init() nc = Foundation.NSDistributedNotificationCenter.defaultCenter() nc.postNotificationName_object_(notificationName, message) del pool SABnzbd-2.3.2/sabnzbd/panic.py0000644000000000000000000001666313217005257014234 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.panic - Send panic message to the browser """ import os import logging import tempfile import ctypes try: import webbrowser except ImportError: webbrowser = None import sabnzbd import sabnzbd.cfg as cfg from sabnzbd.encoding import unicoder PANIC_PORT = 1 PANIC_TEMPL = 2 PANIC_QUEUE = 3 PANIC_OTHER = 5 PANIC_SQLITE = 7 PANIC_HOST = 8 def MSG_BAD_NEWS(): return r''' ''' + T('Problem with') + ''' %s %s

%s %s

 

%s

%s
''' def MSG_BAD_PORT(): return Ta(r''' SABnzbd needs a free tcp/ip port for its internal web server.
Port %s on %s was tried , but it is not available.
Some other software uses the port or SABnzbd is already running.

Please restart SABnzbd with a different port number.''') + \ '''

%s
    %s --server %s:%s

''' + \ Ta(r'If you get this error message again, please try a different number.
') def MSG_BAD_HOST(): return Ta(r''' SABnzbd needs a valid host address for its internal web server.
You have specified an invalid address.
Safe values are localhost and 0.0.0.0

Please restart SABnzbd with a proper host address.''') + \ '''

%s
    %s --server %s:%s

''' def MSG_BAD_QUEUE(): return Ta(r''' SABnzbd detected saved data from an other SABnzbd version
but cannot re-use the data of the other program.

You may want to finish your queue first with the other program.

After that, start this program with the "--clean" option.
This will erase the current queue and history!
SABnzbd read the file "%s".''') + \ '''

%s
    %s --clean

''' def MSG_BAD_TEMPL(): return Ta(r''' SABnzbd cannot find its web interface files in %s.
Please install the program again.

''') def MSG_OTHER(): return T('SABnzbd detected a fatal error:') + '
%s

%s
' def MSG_SQLITE(): return Ta(r''' SABnzbd detected that the file sqlite3.dll is missing.

Some poorly designed virus-scanners remove this file.
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.

''') def panic_message(panic, a=None, b=None): """ Create the panic message from templates """ if sabnzbd.WIN32: os_str = T('Press Startkey+R and type the line (example):') prog_path = '"%s"' % sabnzbd.MY_FULLNAME else: os_str = T('Open a Terminal window and type the line (example):') prog_path = sabnzbd.MY_FULLNAME if panic == PANIC_PORT: newport = int(b) + 1 newport = "%s" % newport msg = MSG_BAD_PORT() % (b, a, os_str, prog_path, a, newport) elif panic == PANIC_TEMPL: msg = MSG_BAD_TEMPL() % a elif panic == PANIC_QUEUE: msg = MSG_BAD_QUEUE() % (a, os_str, prog_path) elif panic == PANIC_SQLITE: msg = MSG_SQLITE() elif panic == PANIC_HOST: msg = MSG_BAD_HOST() % (os_str, prog_path, 'localhost', b) else: msg = MSG_OTHER() % (a, b) msg = MSG_BAD_NEWS() % (sabnzbd.MY_NAME, sabnzbd.__version__, sabnzbd.MY_NAME, sabnzbd.__version__, msg, T('Program did not start!')) if sabnzbd.WIN_SERVICE: sabnzbd.WIN_SERVICE.ErrLogger('Panic exit', msg) if (not cfg.autobrowser()) or sabnzbd.DAEMON: return msgfile, url = tempfile.mkstemp(suffix='.html') os.write(msgfile, msg) os.close(msgfile) return url def panic_port(host, port): show_error_dialog("\n%s:\n %s" % (T('Fatal error'), T('Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running.') % (port, host))) launch_a_browser(panic_message(PANIC_PORT, host, port)) def panic_host(host, port): launch_a_browser(panic_message(PANIC_HOST, host, port)) def panic_queue(name): launch_a_browser(panic_message(PANIC_QUEUE, name, 0)) def panic_tmpl(name): launch_a_browser(panic_message(PANIC_TEMPL, name, 0)) def panic_sqlite(name): launch_a_browser(panic_message(PANIC_SQLITE, name, 0)) def panic(reason, remedy=""): show_error_dialog("\n%s:\n %s\n%s" % (T('Fatal error'), reason, remedy)) launch_a_browser(panic_message(PANIC_OTHER, reason, remedy)) def launch_a_browser(url, force=False): """ Launch a browser pointing to the URL """ if not force and not cfg.autobrowser() or sabnzbd.DAEMON: return if '::1' in url and '[::1]' not in url: # Get around idiosyncrasy in Python runtime url = url.replace('::1', '[::1]') if cfg.enable_https() and not cfg.https_port.get_int(): # Must use https, because http is not available url = url.replace('http:', 'https:') if 'localhost' in url and not cfg.ipv6_hosting(): url = url.replace('localhost', '127.0.0.1') logging.info("Launching browser with %s", url) try: if url and not url.startswith('http'): url = 'file:///%s' % url if webbrowser: webbrowser.open(url, 2, 1) else: logging.info('Not showing panic message in webbrowser, no support found') except: logging.warning(T('Cannot launch the browser, probably not found')) logging.info("Traceback: ", exc_info=True) def show_error_dialog(msg): """ Show a pop-up when program cannot start Windows-only, otherwise only print to console """ if sabnzbd.WIN32: ctypes.windll.user32.MessageBoxW(0, unicoder(msg), T('Fatal error'), 0) print msg def error_page_401(status, message, traceback, version): """ Custom handler for 401 error """ title = T('Access denied') body = T('Error %s: You need to provide a valid username and password.') % status return r''' %s

%s ''' % (title, body) def error_page_404(status, message, traceback, version): """ Custom handler for 404 error, redirect to main page """ return r'''
''' % cfg.url_base() SABnzbd-2.3.2/sabnzbd/par2file.py0000644000000000000000000001224113217005257014632 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.par2file - All par2-related functionality """ import os import logging import re import hashlib import struct PROBABLY_PAR2_RE = re.compile(r'(.*)\.vol(\d*)[\+\-](\d*)\.par2', re.I) PAR_ID = "PAR2\x00PKT" PAR_RECOVERY_ID = "RecvSlic" def is_parfile(filename): """ Check quickly whether file has par2 signature """ try: with open(filename, "rb") as f: buf = f.read(8) return buf.startswith(PAR_ID) except: pass return False def analyse_par2(name, filepath=None): """ Check if file is a par2-file and determine vol/block return setname, vol, block setname is empty when not a par2 file """ name = name.strip() setname = None vol = block = 0 m = PROBABLY_PAR2_RE.search(name) if m: setname = m.group(1) vol = m.group(2) block = m.group(3) else: # Base-par2 file setname = os.path.splitext(name)[0].strip() # Could not parse the filename, need deep inspection # We already know it's a par2 from the is_parfile if filepath: try: # Quick loop to find number blocks # Assumes blocks are larger than 128 bytes # Worst case, we only count 1, still good with open(filepath, "rb") as f: buf = f.read(128) while buf: if PAR_RECOVERY_ID in buf: block += 1 buf = f.read(128) except: pass return setname, vol, block def parse_par2_file(nzf, fname): """ Get the hash table and the first-16k hash table from a PAR2 file Return as dictionary, indexed on names or hashes for the first-16 table For a full description of the par2 specification, visit: http://parchive.sourceforge.net/docs/specifications/parity-volume-spec/article-spec.html """ table = {} duplicates16k = [] try: f = open(fname, 'rb') except: return table try: header = f.read(8) while header: name, hash, hash16k = parse_par2_file_packet(f, header) if name: table[name] = hash if hash16k not in nzf.nzo.md5of16k: nzf.nzo.md5of16k[hash16k] = name elif nzf.nzo.md5of16k[hash16k] != name: # Not unique and not already linked to this file # Remove to avoid false-renames duplicates16k.append(hash16k) header = f.read(8) except (struct.error, IndexError): logging.info('Cannot use corrupt par2 file for QuickCheck, "%s"', fname) logging.info('Traceback: ', exc_info=True) table = {} except: logging.debug('QuickCheck parser crashed in file %s', fname) logging.info('Traceback: ', exc_info=True) table = {} f.close() # Have to remove duplicates at the end to make sure # no trace is left in case of multi-duplicates for hash16k in duplicates16k: if hash16k in nzf.nzo.md5of16k: old_name = nzf.nzo.md5of16k.pop(hash16k) logging.debug('Par2-16k signature of %s not unique, discarding', old_name) return table def parse_par2_file_packet(f, header): """ Look up and analyze a FileDesc package """ nothing = None, None, None if header != PAR_ID: return nothing # Length must be multiple of 4 and at least 20 len = struct.unpack(' # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.postproc - threaded post-processing of jobs """ import os import Queue import logging import sabnzbd import xml.sax.saxutils import time import re from sabnzbd.newsunpack import unpack_magic, par2_repair, external_processing, \ sfv_check, build_filelists, rar_sort from threading import Thread from sabnzbd.misc import real_path, get_unique_path, create_dirs, move_to_path, \ make_script_path, long_path, clip_path, \ on_cleanup_list, renamer, remove_dir, remove_all, globber, globber_full, \ set_permissions, cleanup_empty_directories, fix_unix_encoding, \ sanitize_and_trim_path, sanitize_files_in_folder, remove_file from sabnzbd.sorting import Sorter from sabnzbd.constants import REPAIR_PRIORITY, TOP_PRIORITY, POSTPROC_QUEUE_FILE_NAME, \ POSTPROC_QUEUE_VERSION, sample_match, JOB_ADMIN, Status, VERIFIED_FILE from sabnzbd.encoding import TRANS, unicoder from sabnzbd.rating import Rating import sabnzbd.emailer as emailer import sabnzbd.dirscanner as dirscanner import sabnzbd.downloader import sabnzbd.config as config import sabnzbd.cfg as cfg import sabnzbd.nzbqueue import sabnzbd.database as database import sabnzbd.notifier as notifier import sabnzbd.utils.rarfile as rarfile import sabnzbd.utils.checkdir MAX_FAST_JOB_COUNT = 3 # Match samples RE_SAMPLE = re.compile(sample_match, re.I) class PostProcessor(Thread): """ PostProcessor thread, designed as Singleton """ do = None # Link to instance of the thread def __init__(self): """ Initialize PostProcessor thread """ Thread.__init__(self) # This history queue is simply used to log what active items to display in the web_ui self.load() if self.history_queue is None: self.history_queue = [] # Fast-queue for jobs already finished by DirectUnpack self.fast_queue = Queue.Queue() # Regular queue for jobs that might need more attention self.slow_queue = Queue.Queue() # Load all old jobs for nzo in self.history_queue: self.process(nzo) # Counter to not only process fast-jobs self.__fast_job_count = 0 # State variables self.__stop = False self.__busy = False self.paused = False PostProcessor.do = self def save(self): """ Save postproc queue """ logging.info("Saving postproc queue") sabnzbd.save_admin((POSTPROC_QUEUE_VERSION, self.history_queue), POSTPROC_QUEUE_FILE_NAME) def load(self): """ Save postproc queue """ self.history_queue = [] logging.info("Loading postproc queue") data = sabnzbd.load_admin(POSTPROC_QUEUE_FILE_NAME) if data is None: return try: version, history_queue = data if POSTPROC_QUEUE_VERSION != version: logging.warning(T('Old queue detected, use Status->Repair to convert the queue')) elif isinstance(history_queue, list): self.history_queue = [nzo for nzo in history_queue if os.path.exists(nzo.downpath)] except: logging.info('Corrupt %s file, discarding', POSTPROC_QUEUE_FILE_NAME) logging.info("Traceback: ", exc_info=True) def delete(self, nzo_id, del_files=False): """ Remove a job from the post processor queue """ for nzo in self.history_queue: if nzo.nzo_id == nzo_id: if nzo.status in (Status.FAILED, Status.COMPLETED): nzo.to_be_removed = True elif nzo.status in (Status.DOWNLOADING, Status.QUEUED): self.remove(nzo) nzo.purge_data(keep_basic=False, del_files=del_files) logging.info('Removed job %s from postproc queue', nzo.work_name) nzo.work_name = '' # Mark as deleted job break def process(self, nzo): """ Push on finished job in the queue """ if nzo not in self.history_queue: self.history_queue.append(nzo) # Fast-track if it has DirectUnpacked jobs or if it's still going if nzo.direct_unpacker and (nzo.direct_unpacker.success_sets or not nzo.direct_unpacker.killed): self.fast_queue.put(nzo) else: self.slow_queue.put(nzo) self.save() sabnzbd.history_updated() def remove(self, nzo): """ Remove given nzo from the queue """ try: self.history_queue.remove(nzo) except: pass self.save() sabnzbd.history_updated() def stop(self): """ Stop thread after finishing running job """ self.__stop = True self.slow_queue.put(None) self.fast_queue.put(None) def cancel_pp(self, nzo_id): """ Change the status, so that the PP is canceled """ for nzo in self.history_queue: if nzo.nzo_id == nzo_id: nzo.abort_direct_unpacker() if nzo.pp_active: nzo.pp_active = False return True return None def empty(self): """ Return True if pp queue is empty """ return self.slow_queue.empty() and self.fast_queue.empty() and not self.__busy def get_queue(self): """ Return list of NZOs that still need to be processed """ return [nzo for nzo in self.history_queue if nzo.work_name] def get_path(self, nzo_id): """ Return download path for given nzo_id or None when not found """ for nzo in self.history_queue: if nzo.nzo_id == nzo_id: return nzo.downpath return None def run(self): """ Postprocessor loop """ # First we do a dircheck complete_dir = sabnzbd.cfg.complete_dir.get_path() if sabnzbd.utils.checkdir.isFAT(complete_dir): logging.warning(T('Completed Download Folder %s is on FAT file system, limiting maximum file size to 4GB') % complete_dir) else: logging.info("Completed Download Folder %s is not on FAT", complete_dir) # Check on Windows if we have unicode-subprocess if sabnzbd.WIN32: try: import subprocessww except ImportError: logging.warning(T('Module subprocessww missing. Expect problems with Unicoded file and directory names in downloads.')) # Do a pruge of the history-items if it was set, just to be sure history_db = database.HistoryDB() history_db.auto_history_purge() history_db.close() # Start looping check_eoq = False while not self.__stop: self.__busy = False if self.paused: time.sleep(5) continue # Something in the fast queue? try: # Every few fast-jobs we should check allow a # slow job so that they don't wait forever if self.__fast_job_count >= MAX_FAST_JOB_COUNT and self.slow_queue.qsize(): raise Queue.Empty nzo = self.fast_queue.get(timeout=2) self.__fast_job_count += 1 except Queue.Empty: # Try the slow queue try: nzo = self.slow_queue.get(timeout=2) # Reset fast-counter self.__fast_job_count = 0 except Queue.Empty: # Check for empty queue if check_eoq: check_eoq = False handle_empty_queue() # No fast or slow jobs, better luck next loop! continue # Stop job if not nzo: continue # Job was already deleted. if not nzo.work_name: check_eoq = True continue # Flag NZO as being processed nzo.pp_active = True # Pause downloader, if users wants that if cfg.pause_on_post_processing(): sabnzbd.downloader.Downloader.do.wait_for_postproc() self.__busy = True process_job(nzo) if nzo.to_be_removed: history_db = database.HistoryDB() history_db.remove_history(nzo.nzo_id) history_db.close() nzo.purge_data(keep_basic=False, del_files=True) # Processing done nzo.pp_active = False self.remove(nzo) check_eoq = True # Allow download to proceed sabnzbd.downloader.Downloader.do.resume_from_postproc() def process_job(nzo): """ Process one job """ start = time.time() # keep track of whether we can continue all_ok = True # keep track of par problems par_error = False # keep track of any unpacking errors unpack_error = False # Signal empty download, for when 'empty_postproc' is enabled empty = False nzb_list = [] # These need to be initialized in case of a crash workdir_complete = '' postproc_time = 0 script_log = '' script_line = '' # Get the job flags nzo.save_attribs() flag_repair, flag_unpack, flag_delete = nzo.repair_opts # Normalize PP if flag_delete: flag_unpack = True if flag_unpack: flag_repair = True # Get the NZB name filename = nzo.final_name if nzo.fail_msg: # Special case: aborted due to too many missing data nzo.status = Status.FAILED nzo.save_attribs() all_ok = False par_error = True unpack_error = 1 try: # Get the folder containing the download result workdir = nzo.downpath tmp_workdir_complete = None # if no files are present (except __admin__), fail the job if all_ok and len(globber(workdir)) < 2: if nzo.precheck: _enough, ratio = nzo.check_quality() req_ratio = float(cfg.req_completion_rate()) / 100.0 # Make sure that rounded ratio doesn't equal required ratio # when it is actually below required if (ratio < req_ratio) and (req_ratio - ratio) < 0.001: ratio = req_ratio - 0.001 emsg = '%.1f%%' % (ratio * 100.0) emsg2 = '%.1f%%' % float(cfg.req_completion_rate()) emsg = T('Download might fail, only %s of required %s available') % (emsg, emsg2) else: emsg = T('Download failed - Not on your server(s)') empty = True emsg += ' - https://sabnzbd.org/not-complete' nzo.fail_msg = emsg nzo.set_unpack_info('Fail', emsg) nzo.status = Status.FAILED # do not run unpacking or parity verification flag_repair = flag_unpack = False all_ok = cfg.empty_postproc() and empty if not all_ok: par_error = True unpack_error = 1 script = nzo.script cat = nzo.cat logging.info('Starting Post-Processing on %s' + ' => Repair:%s, Unpack:%s, Delete:%s, Script:%s, Cat:%s', filename, flag_repair, flag_unpack, flag_delete, script, nzo.cat) # Set complete dir to workdir in case we need to abort workdir_complete = workdir marker_file = None # Par processing, if enabled if all_ok and flag_repair: par_error, re_add = parring(nzo, workdir) if re_add: # Try to get more par files return False # If we don't need extra par2, we can disconnect if sabnzbd.nzbqueue.NzbQueue.do.actives(grabs=False) == 0 and cfg.autodisconnect(): # This was the last job, close server connections sabnzbd.downloader.Downloader.do.disconnect() # Sanitize the resulting files if sabnzbd.WIN32: sanitize_files_in_folder(workdir) # Check if user allows unsafe post-processing if flag_repair and cfg.safe_postproc(): all_ok = all_ok and not par_error if all_ok: # Fix encodings fix_unix_encoding(workdir) # Use dirs generated by direct-unpacker if nzo.direct_unpacker and nzo.direct_unpacker.unpack_dir_info: tmp_workdir_complete, workdir_complete, file_sorter, one_folder, marker_file = nzo.direct_unpacker.unpack_dir_info else: # Generate extraction path tmp_workdir_complete, workdir_complete, file_sorter, one_folder, marker_file = prepare_extraction_path(nzo) newfiles = [] # Run Stage 2: Unpack if flag_unpack: if all_ok: # set the current nzo status to "Extracting...". Used in History nzo.status = Status.EXTRACTING logging.info("Running unpack_magic on %s", filename) unpack_error, newfiles = unpack_magic(nzo, workdir, tmp_workdir_complete, flag_delete, one_folder, (), (), (), (), ()) if sabnzbd.WIN32: # Sanitize the resulting files newfiles = sanitize_files_in_folder(tmp_workdir_complete) logging.info("unpack_magic finished on %s", filename) else: nzo.set_unpack_info('Unpack', T('No post-processing because of failed verification')) if cfg.safe_postproc(): all_ok = all_ok and not unpack_error if all_ok: # Move any (left-over) files to destination nzo.status = Status.MOVING nzo.set_action_line(T('Moving'), '...') for root, _dirs, files in os.walk(workdir): if not root.endswith(JOB_ADMIN): for file_ in files: path = os.path.join(root, file_) new_path = path.replace(workdir, tmp_workdir_complete) ok, new_path = move_to_path(path, new_path) if new_path: newfiles.append(new_path) if not ok: nzo.set_unpack_info('Unpack', T('Failed moving %s to %s') % (unicoder(path), unicoder(new_path))) all_ok = False break # Set permissions right set_permissions(tmp_workdir_complete) if all_ok and marker_file: del_marker(os.path.join(tmp_workdir_complete, marker_file)) remove_from_list(marker_file, newfiles) if all_ok: # Remove files matching the cleanup list cleanup_list(tmp_workdir_complete, True) # Check if this is an NZB-only download, if so redirect to queue # except when PP was Download-only if flag_repair: nzb_list = nzb_redirect(tmp_workdir_complete, nzo.final_name, nzo.pp, script, nzo.cat, priority=nzo.priority) else: nzb_list = None if nzb_list: nzo.set_unpack_info('Download', T('Sent %s to queue') % unicoder(nzb_list)) cleanup_empty_directories(tmp_workdir_complete) else: cleanup_list(tmp_workdir_complete, False) script_output = '' script_ret = 0 if not nzb_list: # Give destination its final name if cfg.folder_rename() and tmp_workdir_complete and not one_folder: if all_ok: try: newfiles = rename_and_collapse_folder(tmp_workdir_complete, workdir_complete, newfiles) except: logging.error(T('Error renaming "%s" to "%s"'), clip_path(tmp_workdir_complete), clip_path(workdir_complete)) logging.info('Traceback: ', exc_info=True) # Better disable sorting because filenames are all off now file_sorter.sort_file = None else: workdir_complete = tmp_workdir_complete.replace('_UNPACK_', '_FAILED_') workdir_complete = get_unique_path(workdir_complete, n=0, create_dir=False) workdir_complete = workdir_complete if empty: job_result = -1 else: job_result = int(par_error) + int(bool(unpack_error)) * 2 if cfg.ignore_samples(): remove_samples(workdir_complete) # TV/Movie/Date Renaming code part 2 - rename and move files to parent folder if all_ok and file_sorter.sort_file: if newfiles: file_sorter.rename(newfiles, workdir_complete) workdir_complete, ok = file_sorter.move(workdir_complete) else: workdir_complete, ok = file_sorter.rename_with_ext(workdir_complete) if not ok: nzo.set_unpack_info('Unpack', T('Failed to move files')) all_ok = False # Run the user script script_path = make_script_path(script) if (all_ok or not cfg.safe_postproc()) and (not nzb_list) and script_path: # Set the current nzo status to "Ext Script...". Used in History nzo.status = Status.RUNNING nzo.set_action_line(T('Running script'), unicoder(script)) nzo.set_unpack_info('Script', T('Running user script %s') % unicoder(script), unique=True) script_log, script_ret = external_processing(script_path, nzo, clip_path(workdir_complete), nzo.final_name, job_result) script_line = get_last_line(script_log) if script_log: script_output = nzo.nzo_id if script_line: nzo.set_unpack_info('Script', unicoder(script_line), unique=True) else: nzo.set_unpack_info('Script', T('Ran %s') % unicoder(script), unique=True) else: script = "" script_line = "" script_ret = 0 # Maybe bad script result should fail job if script_ret and cfg.script_can_fail(): script_error = True all_ok = False nzo.fail_msg = T('Script exit code is %s') % script_ret else: script_error = False # Email the results if (not nzb_list) and cfg.email_endjob(): if (cfg.email_endjob() == 1) or (cfg.email_endjob() == 2 and (unpack_error or par_error or script_error)): emailer.endjob(nzo.final_name, nzo.cat, all_ok, workdir_complete, nzo.bytes_downloaded, nzo.fail_msg, nzo.unpack_info, script, TRANS(script_log), script_ret) if script_output: # Can do this only now, otherwise it would show up in the email if script_ret: script_ret = 'Exit(%s) ' % script_ret else: script_ret = '' if len(script_log.rstrip().split('\n')) > 1: nzo.set_unpack_info('Script', u'%s%s (%s)' % (script_ret, script_line, xml.sax.saxutils.escape(script_output), T('More')), unique=True) else: # No '(more)' button needed nzo.set_unpack_info('Script', u'%s%s ' % (script_ret, script_line), unique=True) # Cleanup again, including NZB files if all_ok: cleanup_list(workdir_complete, False) # Force error for empty result all_ok = all_ok and not empty # Update indexer with results if cfg.rating_enable(): if nzo.encrypted > 0: Rating.do.update_auto_flag(nzo.nzo_id, Rating.FLAG_ENCRYPTED) if empty: hosts = map(lambda s: s.host, sabnzbd.downloader.Downloader.do.nzo_servers(nzo)) if not hosts: hosts = [None] for host in hosts: Rating.do.update_auto_flag(nzo.nzo_id, Rating.FLAG_EXPIRED, host) except: logging.error(T('Post Processing Failed for %s (%s)'), filename, T('see logfile')) logging.info("Traceback: ", exc_info=True) nzo.fail_msg = T('PostProcessing was aborted (%s)') % T('see logfile') notifier.send_notification(T('Download Failed'), filename, 'failed', nzo.cat) nzo.status = Status.FAILED par_error = True all_ok = False if cfg.email_endjob(): emailer.endjob(nzo.final_name, nzo.cat, all_ok, clip_path(workdir_complete), nzo.bytes_downloaded, nzo.fail_msg, nzo.unpack_info, '', '', 0) if all_ok: # If the folder only contains one file OR folder, have that as the path # Be aware that series/generic/date sorting may move a single file into a folder containing other files workdir_complete = one_file_or_folder(workdir_complete) workdir_complete = os.path.normpath(workdir_complete) # Clean up the NZO try: logging.info('Cleaning up %s (keep_basic=%s)', filename, str(not all_ok)) sabnzbd.nzbqueue.NzbQueue.do.cleanup_nzo(nzo, keep_basic=not all_ok) except: logging.error(T('Cleanup of %s failed.'), nzo.final_name) logging.info("Traceback: ", exc_info=True) # Remove download folder if all_ok: try: if os.path.exists(workdir): logging.debug('Removing workdir %s', workdir) remove_all(workdir, recursive=True) except: logging.error(T('Error removing workdir (%s)'), clip_path(workdir)) logging.info("Traceback: ", exc_info=True) # Use automatic retry link on par2 errors and encrypted/bad RARs if par_error or unpack_error in (2, 3): try_alt_nzb(nzo) # Show final status in history if all_ok: notifier.send_notification(T('Download Completed'), filename, 'complete', nzo.cat) nzo.status = Status.COMPLETED else: notifier.send_notification(T('Download Failed'), filename, 'failed', nzo.cat) nzo.status = Status.FAILED # Log the overall time taken for postprocessing postproc_time = int(time.time() - start) # Create the history DB instance history_db = database.HistoryDB() # Add the nzo to the database. Only the path, script and time taken is passed # Other information is obtained from the nzo history_db.add_history_db(nzo, clip_path(workdir_complete), nzo.downpath, postproc_time, script_log, script_line) # Purge items history_db.auto_history_purge() # The connection is only used once, so close it here history_db.close() sabnzbd.history_updated() return True def prepare_extraction_path(nzo): """ Based on the information that we have, generate the extraction path and create the directory. Separated so it can be called from DirectUnpacker """ one_folder = False marker_file = None # Determine class directory catdir = config.get_categories(nzo.cat).dir() if catdir.endswith('*'): catdir = catdir.strip('*') one_folder = True complete_dir = real_path(cfg.complete_dir.get_path(), catdir) complete_dir = long_path(complete_dir) # TV/Movie/Date Renaming code part 1 - detect and construct paths if cfg.enable_meta(): file_sorter = Sorter(nzo, nzo.cat) else: file_sorter = Sorter(None, nzo.cat) complete_dir = file_sorter.detect(nzo.final_name, complete_dir) if file_sorter.sort_file: one_folder = False complete_dir = sanitize_and_trim_path(complete_dir) if one_folder: workdir_complete = create_dirs(complete_dir) else: workdir_complete = get_unique_path(os.path.join(complete_dir, nzo.final_name), create_dir=True) marker_file = set_marker(workdir_complete) if not workdir_complete or not os.path.exists(workdir_complete): logging.error(T('Cannot create final folder %s') % unicoder(os.path.join(complete_dir, nzo.final_name))) raise IOError if cfg.folder_rename() and not one_folder: prefixed_path = prefix(workdir_complete, '_UNPACK_') tmp_workdir_complete = get_unique_path(prefix(workdir_complete, '_UNPACK_'), create_dir=False) try: renamer(workdir_complete, tmp_workdir_complete) except: pass # On failure, just use the original name # Is the unique path different? Then we also need to modify the final path if prefixed_path != tmp_workdir_complete: workdir_complete = workdir_complete + os.path.splitext(tmp_workdir_complete)[1] else: tmp_workdir_complete = workdir_complete return tmp_workdir_complete, workdir_complete, file_sorter, one_folder, marker_file def parring(nzo, workdir): """ Perform par processing. Returns: (par_error, re_add) """ filename = nzo.final_name notifier.send_notification(T('Post-processing'), filename, 'pp', nzo.cat) logging.info('Starting verification and repair of %s', filename) # Get verification status of sets verified = sabnzbd.load_data(VERIFIED_FILE, nzo.workpath, remove=False) or {} repair_sets = nzo.extrapars.keys() re_add = False par_error = False single = len(repair_sets) == 1 if repair_sets: for setname in repair_sets: if cfg.ignore_samples() and RE_SAMPLE.search(setname.lower()): continue if not verified.get(setname, False): logging.info("Running verification and repair on set %s", setname) parfile_nzf = nzo.partable[setname] # Check if file maybe wasn't deleted and if we maybe have more files in the parset if os.path.exists(os.path.join(nzo.downpath, parfile_nzf.filename)) or nzo.extrapars[setname]: need_re_add, res = par2_repair(parfile_nzf, nzo, workdir, setname, single=single) # Was it aborted? if not nzo.pp_active: re_add = False par_error = True break re_add = re_add or need_re_add verified[setname] = res else: continue par_error = par_error or not res else: # We must not have found any par2.. logging.info("No par2 sets for %s", filename) nzo.set_unpack_info('Repair', T('[%s] No par2 sets') % unicoder(filename)) if cfg.sfv_check() and not verified.get('', False): par_error = not try_sfv_check(nzo, workdir, '') verified[''] = not par_error # If still no success, do RAR-check if not par_error and cfg.enable_unrar(): par_error = not try_rar_check(nzo, workdir, '') verified[''] = not par_error if re_add: logging.info('Re-added %s to queue', filename) if nzo.priority != TOP_PRIORITY: nzo.priority = REPAIR_PRIORITY nzo.status = Status.FETCHING sabnzbd.nzbqueue.NzbQueue.do.add(nzo) sabnzbd.downloader.Downloader.do.resume_from_postproc() sabnzbd.save_data(verified, VERIFIED_FILE, nzo.workpath) logging.info('Verification and repair finished for %s', filename) return par_error, re_add def try_sfv_check(nzo, workdir, setname): """ Attempt to verify set using SFV file Return True if verified, False when failed When setname is '', all SFV files will be used, otherwise only the matching one When setname is '' and no SFV files are found, True is returned """ # Get list of SFV names; shortest name first, minimizes the chance on a mismatch sfvs = globber_full(workdir, '*.sfv') sfvs.sort(lambda x, y: len(x) - len(y)) par_error = False found = False for sfv in sfvs: if setname.lower() in os.path.basename(sfv).lower(): found = True nzo.status = Status.VERIFYING nzo.set_unpack_info('Repair', T('Trying SFV verification')) nzo.set_action_line(T('Trying SFV verification'), '...') failed = sfv_check(sfv) if failed: fail_msg = T('Some files failed to verify against "%s"') % unicoder(os.path.basename(sfv)) msg = fail_msg + '; ' msg += '; '.join(failed) nzo.set_unpack_info('Repair', msg) par_error = True else: nzo.set_unpack_info('Repair', T('Verified successfully using SFV files')) if setname: break # Show error in GUI if found and par_error: nzo.status = Status.FAILED nzo.fail_msg = fail_msg return (found or not setname) and not par_error def try_rar_check(nzo, workdir, setname): """ Attempt to verify set using the RARs Return True if verified, False when failed When setname is '', all RAR files will be used, otherwise only the matching one If no RAR's are found, returns True """ _, _, rars, _, _ = build_filelists(workdir) if setname: # Filter based on set rars = [rar for rar in rars if os.path.basename(rar).startswith(setname)] # Sort rars.sort(rar_sort) # Test if rars: nzo.status = Status.VERIFYING nzo.set_unpack_info('Repair', T('Trying RAR-based verification')) nzo.set_action_line(T('Trying RAR-based verification'), '...') try: # Set path to unrar and open the file # Requires de-unicode for RarFile to work! rarfile.UNRAR_TOOL = sabnzbd.newsunpack.RAR_COMMAND zf = rarfile.RarFile(rars[0]) # Skip if it's encrypted if zf.needs_password(): msg = T('[%s] RAR-based verification failed: %s') % (unicoder(os.path.basename(rars[0])), T('Passworded')) nzo.set_unpack_info('Repair', msg) return True # Will throw exception if something is wrong zf.testrar() # Success! msg = T('RAR files verified successfully') nzo.set_unpack_info('Repair', msg) logging.info(msg) return True except rarfile.Error as e: nzo.fail_msg = T('RAR files failed to verify') msg = T('[%s] RAR-based verification failed: %s') % (unicoder(os.path.basename(rars[0])), unicoder(e.message.replace('\r\n', ' '))) nzo.set_unpack_info('Repair', msg) logging.info(msg) return False else: # No rar-files, so just continue return True def handle_empty_queue(): """ Check if empty queue calls for action """ if sabnzbd.nzbqueue.NzbQueue.do.actives() == 0: sabnzbd.save_state() # Perform end-of-queue action when one is set if sabnzbd.QUEUECOMPLETEACTION: logging.info("Queue has finished, launching: %s (%s)", sabnzbd.QUEUECOMPLETEACTION, sabnzbd.QUEUECOMPLETEARG) if sabnzbd.QUEUECOMPLETEARG: sabnzbd.QUEUECOMPLETEACTION(sabnzbd.QUEUECOMPLETEARG) else: Thread(target=sabnzbd.QUEUECOMPLETEACTION).start() sabnzbd.change_queue_complete_action(cfg.queue_complete(), new=False) def cleanup_list(wdir, skip_nzb): """ Remove all files whose extension matches the cleanup list, optionally ignoring the nzb extension """ if cfg.cleanup_list(): try: files = os.listdir(wdir) except: files = () for filename in files: path = os.path.join(wdir, filename) if os.path.isdir(path): cleanup_list(path, skip_nzb) else: if on_cleanup_list(filename, skip_nzb): try: logging.info("Removing unwanted file %s", path) remove_file(path) except: logging.error(T('Removing %s failed'), clip_path(path)) logging.info("Traceback: ", exc_info=True) if files: try: remove_dir(wdir) except: pass def prefix(path, pre): """ Apply prefix to last part of path '/my/path' and 'hi_' will give '/my/hi_path' """ p, d = os.path.split(path) return os.path.join(p, pre + d) def nzb_redirect(wdir, nzbname, pp, script, cat, priority): """ Check if this job contains only NZB files, if so send to queue and remove if on CleanList Returns list of processed NZB's """ files = [] for root, _dirs, names in os.walk(wdir): for name in names: files.append(os.path.join(root, name)) for file_ in files: if os.path.splitext(file_)[1].lower() != '.nzb': return None # For multiple NZBs, cannot use the current job name if len(files) != 1: nzbname = None # Process all NZB files for file_ in files: dirscanner.ProcessSingleFile(os.path.split(file_)[1], file_, pp, script, cat, priority=priority, keep=False, dup_check=False, nzbname=nzbname) return files def one_file_or_folder(folder): """ If the dir only contains one file or folder, join that file/folder onto the path """ if os.path.exists(folder) and os.path.isdir(folder): try: cont = os.listdir(folder) if len(cont) == 1: folder = os.path.join(folder, cont[0]) folder = one_file_or_folder(folder) except WindowsError: # Can occur on paths it doesn't like, for example "C:" pass return folder TAG_RE = re.compile(r'<[^>]+>') def get_last_line(txt): """ Return last non-empty line of a text, trim to 150 max """ # First we remove HTML code in a basic way txt = TAG_RE.sub(' ', txt) # Then we get the last line lines = txt.split('\n') n = len(lines) - 1 while n >= 0 and not lines[n].strip('\r\t '): n = n - 1 line = lines[n].strip('\r\t ') if len(line) >= 150: line = line[:147] + '...' return line def remove_samples(path): """ Remove all files that match the sample pattern """ for root, _dirs, files in os.walk(path): for file_ in files: if RE_SAMPLE.search(file_): path = os.path.join(root, file_) try: logging.info("Removing unwanted sample file %s", path) remove_file(path) except: logging.error(T('Removing %s failed'), clip_path(path)) logging.info("Traceback: ", exc_info=True) def rename_and_collapse_folder(oldpath, newpath, files): """ Rename folder, collapsing when there's just a single subfolder oldpath --> newpath OR oldpath/subfolder --> newpath Modify list of filenames accordingly """ orgpath = oldpath items = globber(oldpath) if len(items) == 1: folder = items[0] folder_path = os.path.join(oldpath, folder) if os.path.isdir(folder_path) and folder not in ('VIDEO_TS', 'AUDIO_TS'): logging.info('Collapsing %s', os.path.join(newpath, folder)) oldpath = folder_path oldpath = os.path.normpath(oldpath) newpath = os.path.normpath(newpath) files = [os.path.normpath(f).replace(oldpath, newpath) for f in files] renamer(oldpath, newpath) try: remove_dir(orgpath) except: pass return files def set_marker(folder): """ Set marker file and return name """ name = cfg.marker_file() if name: path = os.path.join(folder, name) logging.debug('Create marker file %s', path) try: fp = open(path, 'w') fp.close() except: logging.info('Cannot create marker file %s', path) logging.info("Traceback: ", exc_info=True) name = None return name def del_marker(path): """ Remove marker file """ if path and os.path.exists(path): logging.debug('Removing marker file %s', path) try: remove_file(path) except: logging.info('Cannot remove marker file %s', path) logging.info("Traceback: ", exc_info=True) def remove_from_list(name, lst): if name: for n in xrange(len(lst)): if lst[n].endswith(name): logging.debug('Popping %s', lst[n]) lst.pop(n) return def try_alt_nzb(nzo): """ Try to get a new NZB if available """ url = nzo.nzo_info.get('failure') if url and cfg.new_nzb_on_failure(): sabnzbd.add_url(url, nzo.pp, nzo.script, nzo.cat, nzo.priority) SABnzbd-2.3.2/sabnzbd/powersup.py0000644000000000000000000002173713217005257015024 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.powersup - System power management support """ import os import subprocess import logging import time ############################################################################## # Power management for Windows ############################################################################## try: import win32security import win32api import ntsecuritycon except ImportError: pass def win_power_privileges(): """ To do any power-options, the process needs higher privileges """ flags = ntsecuritycon.TOKEN_ADJUST_PRIVILEGES | ntsecuritycon.TOKEN_QUERY htoken = win32security.OpenProcessToken(win32api.GetCurrentProcess(), flags) id_ = win32security.LookupPrivilegeValue(None, ntsecuritycon.SE_SHUTDOWN_NAME) newPrivileges = [(id_, ntsecuritycon.SE_PRIVILEGE_ENABLED)] win32security.AdjustTokenPrivileges(htoken, 0, newPrivileges) def win_hibernate(): """ Hibernate Windows system, returns after wakeup """ try: win_power_privileges() win32api.SetSystemPowerState(False, True) except: logging.error(T('Failed to hibernate system')) logging.info("Traceback: ", exc_info=True) def win_standby(): """ Standby Windows system, returns after wakeup """ try: win_power_privileges() win32api.SetSystemPowerState(True, True) except: logging.error(T('Failed to standby system')) logging.info("Traceback: ", exc_info=True) def win_shutdown(): """ Shutdown Windows system, never returns """ try: win_power_privileges() win32api.InitiateSystemShutdown("", "", 30, 1, 0) finally: os._exit(0) ############################################################################## # Power management for OSX ############################################################################## def osx_shutdown(): """ Shutdown OSX system, never returns """ try: subprocess.call(['osascript', '-e', 'tell app "System Events" to shut down']) except: logging.error(T('Error while shutting down system')) logging.info("Traceback: ", exc_info=True) os._exit(0) def osx_standby(): """ Make OSX system sleep, returns after wakeup """ try: subprocess.call(['osascript', '-e', 'tell app "System Events" to sleep']) time.sleep(10) except: logging.error(T('Failed to standby system')) logging.info("Traceback: ", exc_info=True) def osx_hibernate(): """ Make OSX system sleep, returns after wakeup """ osx_standby() ############################################################################## # Power management for Linux ############################################################################## # Requires DBus plus either HAL [1] or the more modern ConsoleKit [2] and # DeviceKit(-power) [3]. HAL will eventually be deprecated but older systems # might still use it. # [1] http://people.freedesktop.org/~hughsient/temp/dbus-interface.html # [2] http://www.freedesktop.org/software/ConsoleKit/doc/ConsoleKit.html # [3] http://hal.freedesktop.org/docs/DeviceKit-power/ # # Original code was contributed by Marcel de Vries # try: import dbus HAVE_DBUS = True except ImportError: HAVE_DBUS = False _IS_NOT_INTERACTIVE = False _LOGIND_SUCCESSFUL_RESULT = 'yes' def _get_sessionproxy(): """ Return (proxy-object, interface), (None, None) if not available """ name = 'org.freedesktop.PowerManagement' path = '/org/freedesktop/PowerManagement' interface = 'org.freedesktop.PowerManagement' try: bus = dbus.SessionBus() return bus.get_object(name, path), interface except dbus.exceptions.DBusException: return None, None def _get_systemproxy(method): """ Return (proxy-object, interface, pinterface), (None, None, None) if not available """ if method == 'ConsoleKit': name = 'org.freedesktop.ConsoleKit' path = '/org/freedesktop/ConsoleKit/Manager' interface = 'org.freedesktop.ConsoleKit.Manager' pinterface = None elif method == 'DeviceKit': name = 'org.freedesktop.DeviceKit.Power' path = '/org/freedesktop/DeviceKit/Power' interface = 'org.freedesktop.DeviceKit.Power' pinterface = 'org.freedesktop.DBus.Properties' elif method == 'UPower': name = 'org.freedesktop.UPower' path = '/org/freedesktop/UPower' interface = 'org.freedesktop.UPower' pinterface = 'org.freedesktop.DBus.Properties' elif method == 'Logind': name = 'org.freedesktop.login1' path = '/org/freedesktop/login1' interface = 'org.freedesktop.login1.Manager' pinterface = None try: bus = dbus.SystemBus() return bus.get_object(name, path), interface, pinterface except dbus.exceptions.DBusException, msg: logging.info('DBus not reachable (%s)', msg) return None, None, None def linux_shutdown(): """ Make Linux system shutdown, never returns """ if not HAVE_DBUS: os._exit(0) try: proxy, interface = _get_sessionproxy() if proxy: if proxy.CanShutdown(): proxy.Shutdown(dbus_interface=interface) else: proxy, interface, pinterface = _get_systemproxy('Logind') if proxy: if proxy.CanPowerOff(dbus_interface=interface) == _LOGIND_SUCCESSFUL_RESULT: proxy.PowerOff(_IS_NOT_INTERACTIVE, dbus_interface=interface) else: proxy, interface, _pinterface = _get_systemproxy('ConsoleKit') if proxy: if proxy.CanStop(dbus_interface=interface): proxy.Stop(dbus_interface=interface) else: logging.info('DBus does not support Stop (shutdown)') except dbus.exceptions.DBusException, msg: logging.error('Received a DBus exception %s', msg) os._exit(0) def linux_hibernate(): """ Make Linux system go into hibernate, returns after wakeup """ if not HAVE_DBUS: return try: proxy, interface = _get_sessionproxy() if proxy: if proxy.CanHibernate(): proxy.Hibernate(dbus_interface=interface) else: proxy, interface, pinterface = _get_systemproxy('Logind') if proxy: if proxy.CanHibernate(dbus_interface=interface) == _LOGIND_SUCCESSFUL_RESULT: proxy.Hibernate(_IS_NOT_INTERACTIVE, dbus_interface=interface) else: proxy, interface, pinterface = _get_systemproxy('UPower') if not proxy: proxy, interface, pinterface = _get_systemproxy('DeviceKit') if proxy: if proxy.Get(interface, 'can-hibernate', dbus_interface=pinterface): proxy.Hibernate(dbus_interface=interface) else: logging.info('DBus does not support Hibernate') time.sleep(10) except dbus.exceptions.DBusException, msg: logging.error('Received a DBus exception %s', msg) def linux_standby(): """ Make Linux system go into standby, returns after wakeup """ if not HAVE_DBUS: return try: proxy, interface = _get_sessionproxy() if proxy: if proxy.CanSuspend(): proxy.Suspend(dbus_interface=interface) else: proxy, interface, pinterface = _get_systemproxy('Logind') if proxy: if proxy.CanSuspend(dbus_interface=interface) == _LOGIND_SUCCESSFUL_RESULT: proxy.Suspend(_IS_NOT_INTERACTIVE, dbus_interface=interface) else: proxy, interface, pinterface = _get_systemproxy('UPower') if not proxy: proxy, interface, pinterface = _get_systemproxy('DeviceKit') if proxy: if proxy.Get(interface, 'can-suspend', dbus_interface=pinterface): proxy.Suspend(dbus_interface=interface) else: logging.info('DBus does not support Suspend (standby)') time.sleep(10) except dbus.exceptions.DBusException, msg: logging.error('Received a DBus exception %s', msg) SABnzbd-2.3.2/sabnzbd/rating.py0000644000000000000000000003143413217005257014417 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2012 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.rating - Rating support functions """ import httplib import urllib import urlparse import time import logging import copy import socket import Queue import collections from threading import RLock, Thread import sabnzbd from sabnzbd.decorators import synchronized import sabnzbd.cfg as cfg # A queue which ignores duplicates but maintains ordering class OrderedSetQueue(Queue.Queue): def _init(self, maxsize): self.maxsize = maxsize self.queue = collections.OrderedDict() def _put(self, item): self.queue[item] = None def _get(self): return self.queue.popitem()[0] _RATING_URL = "/releaseRatings/releaseRatings.php" RATING_LOCK = RLock() _g_warnings = 0 def _warn(msg): global _g_warnings _g_warnings += 1 if _g_warnings < 3: logging.warning(msg) def _reset_warn(): global _g_warnings _g_warnings = 0 class NzbRating(object): def __init__(self): self.avg_video = 0 self.avg_video_cnt = 0 self.avg_audio = 0 self.avg_audio_cnt = 0 self.avg_vote_up = 0 self.avg_vote_down = 0 self.user_video = None self.user_audio = None self.user_vote = None self.user_flag = {} self.auto_flag = {} self.changed = 0 class NzbRatingV2(NzbRating): def __init__(self): super(NzbRatingV2, self).__init__() self.avg_spam_cnt = 0 self.avg_spam_confirm = False self.avg_encrypted_cnt = 0 self.avg_encrypted_confirm = False def to_v2(self, rating): self.__dict__.update(rating.__dict__) return self class Rating(Thread): VERSION = 2 VOTE_UP = 1 VOTE_DOWN = 2 FLAG_OK = 0 FLAG_SPAM = 1 FLAG_ENCRYPTED = 2 FLAG_EXPIRED = 3 FLAG_OTHER = 4 FLAG_COMMENT = 5 CHANGED_USER_VIDEO = 0x01 CHANGED_USER_AUDIO = 0x02 CHANGED_USER_VOTE = 0x04 CHANGED_USER_FLAG = 0x08 CHANGED_AUTO_FLAG = 0x10 do = None def __init__(self): Rating.do = self self.shutdown = False self.queue = OrderedSetQueue() try: self.version, self.ratings, self.nzo_indexer_map = sabnzbd.load_admin("Rating.sab", silent=not cfg.rating_enable()) if self.version == 1: ratings = {} for k, v in self.ratings.iteritems(): ratings[k] = NzbRatingV2().to_v2(v) self.ratings = ratings self.version = 2 if self.version != Rating.VERSION: raise Exception() except: self.version = Rating.VERSION self.ratings = {} self.nzo_indexer_map = {} Thread.__init__(self) def stop(self): self.shutdown = True self.queue.put(None) # Unblock queue def run(self): self.shutdown = False while not self.shutdown: time.sleep(1) if not cfg.rating_enable(): continue indexer_id = self.queue.get() try: if indexer_id and not self._send_rating(indexer_id): for unused in range(0, 60): if self.shutdown: break time.sleep(1) self.queue.put(indexer_id) except: pass logging.debug('Stopping ratings') @synchronized(RATING_LOCK) def save(self): if self.ratings and self.nzo_indexer_map: sabnzbd.save_admin((self.version, self.ratings, self.nzo_indexer_map), "Rating.sab") # The same file may be uploaded multiple times creating a new nzo_id each time @synchronized(RATING_LOCK) def add_rating(self, indexer_id, nzo_id, fields): if indexer_id and nzo_id: logging.debug('Add rating (%s, %s: %s, %s, %s, %s)', indexer_id, nzo_id, fields['video'], fields['audio'], fields['voteup'], fields['votedown']) try: rating = self.ratings.get(indexer_id, NzbRatingV2()) if fields['video'] and fields['videocnt']: rating.avg_video = int(float(fields['video'])) rating.avg_video_cnt = int(float(fields['videocnt'])) if fields['audio'] and fields['audiocnt']: rating.avg_audio = int(float(fields['audio'])) rating.avg_audio_cnt = int(float(fields['audiocnt'])) if fields['voteup']: rating.avg_vote_up = int(float(fields['voteup'])) if fields['votedown']: rating.avg_vote_down = int(float(fields['votedown'])) if fields['spam']: rating.avg_spam_cnt = int(float(fields['spam'])) if fields['confirmed-spam']: rating.avg_spam_confirm = (fields['confirmed-spam'].lower() == 'yes') if fields['passworded']: rating.avg_encrypted_cnt = int(float(fields['passworded'])) if fields['confirmed-passworded']: rating.avg_encrypted_confirm = (fields['confirmed-passworded'].lower() == 'yes') # Indexers can supply a full URL or just a host if fields['host']: rating.host = fields['host'][0] if fields['host'] and isinstance(fields['host'], list) else fields['host'] if fields['url']: rating.host = fields['url'][0] if fields['url'] and isinstance(fields['url'], list) else fields['url'] self.ratings[indexer_id] = rating self.nzo_indexer_map[nzo_id] = indexer_id except: pass @synchronized(RATING_LOCK) def update_user_rating(self, nzo_id, video, audio, vote, flag, flag_detail=None): logging.debug('Updating user rating (%s: %s, %s, %s, %s)', nzo_id, video, audio, vote, flag) if nzo_id not in self.nzo_indexer_map: logging.warning(T('Indexer id (%s) not found for ratings file'), nzo_id) return indexer_id = self.nzo_indexer_map[nzo_id] rating = self.ratings[indexer_id] if video: rating.user_video = int(video) rating.avg_video = int((rating.avg_video_cnt * rating.avg_video + rating.user_video) / (rating.avg_video_cnt + 1)) rating.changed = rating.changed | Rating.CHANGED_USER_VIDEO if audio: rating.user_audio = int(audio) rating.avg_audio = int((rating.avg_audio_cnt * rating.avg_audio + rating.user_audio) / (rating.avg_audio_cnt + 1)) rating.changed = rating.changed | Rating.CHANGED_USER_AUDIO if flag: rating.user_flag = {'val': int(flag), 'detail': flag_detail} rating.changed = rating.changed | Rating.CHANGED_USER_FLAG if vote: rating.changed = rating.changed | Rating.CHANGED_USER_VOTE if int(vote) == Rating.VOTE_UP: rating.avg_vote_up += 1 # Update if already a vote if rating.user_vote and rating.user_vote == Rating.VOTE_DOWN: rating.avg_vote_down -= 1 else: rating.avg_vote_down += 1 # Update if already a vote if rating.user_vote and rating.user_vote == Rating.VOTE_UP: rating.avg_vote_up -= 1 rating.user_vote = int(vote) self.queue.put(indexer_id) @synchronized(RATING_LOCK) def update_auto_flag(self, nzo_id, flag, flag_detail=None): if not flag or not cfg.rating_enable() or (nzo_id not in self.nzo_indexer_map): return logging.debug('Updating auto flag (%s: %s)', nzo_id, flag) indexer_id = self.nzo_indexer_map[nzo_id] rating = self.ratings[indexer_id] rating.auto_flag = {'val': int(flag), 'detail': flag_detail} rating.changed = rating.changed | Rating.CHANGED_AUTO_FLAG self.queue.put(indexer_id) @synchronized(RATING_LOCK) def get_rating_by_nzo(self, nzo_id): if nzo_id not in self.nzo_indexer_map: return None return copy.copy(self.ratings[self.nzo_indexer_map[nzo_id]]) @synchronized(RATING_LOCK) def _get_rating_by_indexer(self, indexer_id): return copy.copy(self.ratings[indexer_id]) def _flag_request(self, val, flag_detail, auto): if val == Rating.FLAG_SPAM: return {'m': 'rs', 'auto': auto} if val == Rating.FLAG_ENCRYPTED: return {'m': 'rp', 'auto': auto} if val == Rating.FLAG_EXPIRED: expired_host = flag_detail if flag_detail and len(flag_detail) > 0 else 'Other' return {'m': 'rpr', 'pr': expired_host, 'auto': auto} if (val == Rating.FLAG_OTHER) and flag_detail and len(flag_detail) > 0: return {'m': 'o', 'r': flag_detail} if (val == Rating.FLAG_COMMENT) and flag_detail and len(flag_detail) > 0: return {'m': 'rc', 'r': flag_detail} def _send_rating(self, indexer_id): logging.debug('Updating indexer rating (%s)', indexer_id) api_key = cfg.rating_api_key() rating_host = cfg.rating_host() rating_url = _RATING_URL requests = [] _headers = {'User-agent': 'SABnzbd+/%s' % sabnzbd.version.__version__, 'Content-type': 'application/x-www-form-urlencoded'} rating = self._get_rating_by_indexer(indexer_id) # Requesting info here ensures always have latest information even on retry if hasattr(rating, 'host') and rating.host: host_parsed = urlparse.urlparse(rating.host) rating_host = host_parsed.netloc # Is it an URL or just a HOST? if host_parsed.path and host_parsed.path != '/': rating_url = host_parsed.path + '?' + host_parsed.query if host_parsed.query else host_parsed.path if not rating_host: _warn('%s: %s' % (T('Cannot send, missing required data'), T('Server address'))) return True if not api_key: _warn('%s [%s]: %s - %s' % (T('Cannot send, missing required data'), rating_host, T('API Key'), T('This key provides identity to indexer. Check your profile on the indexer\'s website.'))) return True if rating.changed & Rating.CHANGED_USER_VIDEO: requests.append({'m': 'r', 'r': 'videoQuality', 'rn': rating.user_video}) if rating.changed & Rating.CHANGED_USER_AUDIO: requests.append({'m': 'r', 'r': 'audioQuality', 'rn': rating.user_audio}) if rating.changed & Rating.CHANGED_USER_VOTE: up_down = 'up' if rating.user_vote == Rating.VOTE_UP else 'down' requests.append({'m': 'v', 'v': up_down, 'r': 'overall'}) if rating.changed & Rating.CHANGED_USER_FLAG: requests.append(self._flag_request(rating.user_flag.get('val'), rating.user_flag.get('detail'), 0)) if rating.changed & Rating.CHANGED_AUTO_FLAG: requests.append(self._flag_request(rating.auto_flag.get('val'), rating.auto_flag.get('detail'), 1)) try: conn = httplib.HTTPSConnection(rating_host) for request in filter(lambda r: r is not None, requests): if api_key: request['apikey'] = api_key request['i'] = indexer_id conn.request('POST', rating_url, urllib.urlencode(request), headers=_headers) response = conn.getresponse() response.read() if response.status == httplib.UNAUTHORIZED: _warn('Ratings server unauthorized user') return False elif response.status != httplib.OK: _warn('Ratings server failed to process request (%s, %s)' % (response.status, response.reason)) return False self.ratings[indexer_id].changed = self.ratings[indexer_id].changed & ~rating.changed _reset_warn() return True except: _warn('Problem accessing ratings server: %s' % rating_host) return False SABnzbd-2.3.2/sabnzbd/rss.py0000644000000000000000000006352613217005257013751 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.rss - rss client functionality """ import re import logging import time import datetime import threading import sabnzbd from sabnzbd.constants import RSS_FILE_NAME, DEFAULT_PRIORITY, NORMAL_PRIORITY, DUP_PRIORITY from sabnzbd.decorators import synchronized import sabnzbd.config as config import sabnzbd.cfg as cfg from sabnzbd.misc import cat_convert, wildcard_to_re, cat_to_opts, \ match_str, from_units, int_conv, get_urlbase import sabnzbd.emailer as emailer from sabnzbd.encoding import unicoder, xml_name import sabnzbd.utils.feedparser as feedparser __RSS = None # Global pointer to RSS-scanner instance ############################################################################## # Wrapper functions ############################################################################## def init(): global __RSS __RSS = RSSQueue() def stop(): global __RSS if __RSS: __RSS.stop() try: __RSS.join() except: pass def run_feed(feed, download, ignoreFirst=False, force=False, readout=True): global __RSS if __RSS: return __RSS.run_feed(feed, download, ignoreFirst, force=force, readout=readout) def show_result(feed): global __RSS if __RSS: return __RSS.show_result(feed) def flag_downloaded(feed, fid): global __RSS if __RSS: __RSS.flag_downloaded(feed, fid) def lookup_url(feed, fid): global __RSS if __RSS: return __RSS.lookup_url(feed, fid) def run_method(): global __RSS if __RSS: return __RSS.run() else: return None def next_run(t=None): global __RSS if __RSS: if t: __RSS.next_run = t else: return __RSS.next_run else: return time.time() def save(): global __RSS if __RSS: __RSS.save() def clear_feed(feed): global __RSS if __RSS: __RSS.clear_feed(feed) def clear_downloaded(feed): global __RSS if __RSS: __RSS.clear_downloaded(feed) ############################################################################## def notdefault(item): """ Return True if not 'Default|''|*' """ return bool(item) and str(item).lower() not in ('default', '*', '', str(DEFAULT_PRIORITY)) def convert_filter(text): """ Return compiled regex. If string starts with re: it's a real regex else quote all regex specials, replace '*' by '.*' """ text = text.strip().lower() if text.startswith('re:'): txt = text[3:].strip() else: txt = wildcard_to_re(text) try: return re.compile(txt, re.I) except: logging.debug('Could not compile regex: %s', text) return None def remove_obsolete(jobs, new_jobs): """ Expire G/B links that are not in new_jobs (mark them 'X') Expired links older than 3 days are removed from 'jobs' """ now = time.time() limit = now - 259200 # 3days (3x24x3600) olds = jobs.keys() for old in olds: tm = jobs[old]['time'] if old not in new_jobs: if jobs[old].get('status', ' ')[0] in ('G', 'B'): jobs[old]['status'] = 'X' if jobs[old]['status'] == 'X' and tm < limit: logging.debug("Purging link %s", old) del jobs[old] LOCK = threading.RLock() class RSSQueue(object): def __init__(self): self.jobs = {} self.next_run = time.time() self.shutdown = False try: self.jobs = sabnzbd.load_admin(RSS_FILE_NAME) if self.jobs: for feed in self.jobs: remove_obsolete(self.jobs[feed], self.jobs[feed].keys()) except: logging.warning(T('Cannot read %s'), RSS_FILE_NAME) logging.info("Traceback: ", exc_info=True) # Storage needs to be dict if not self.jobs: self.jobs = {} # jobs is a NAME-indexed dictionary # Each element is link-indexed dictionary # Each element is another dictionary: # status : 'D', 'G', 'B', 'X' (downloaded, good-match, bad-match, obsolete) # '*' added means: from the initial batch # '-' added to 'D' means downloaded, but not displayed anymore # title : Title # url : URL # cat : category # orgcat : category as read from feed # pp : pp # script : script # prio : priority # time : timestamp (used for time-based clean-up) # size : size in bytes # age : age in datetime format as specified by feed # season : season number (if applicable) # episode : episode number (if applicable) def stop(self): self.shutdown = True @synchronized(LOCK) def run_feed(self, feed=None, download=False, ignoreFirst=False, force=False, readout=True): """ Run the query for one URI and apply filters """ self.shutdown = False if not feed: return 'No such feed' newlinks = [] new_downloads = [] # Preparations, get options try: feeds = config.get_rss()[feed] except KeyError: logging.error(T('Incorrect RSS feed description "%s"'), feed) logging.info("Traceback: ", exc_info=True) return T('Incorrect RSS feed description "%s"') % feed uris = feeds.uri() defCat = feeds.cat() import sabnzbd.api if not notdefault(defCat) or defCat not in sabnzbd.api.list_cats(default=False): defCat = None defPP = feeds.pp() if not notdefault(defPP): defPP = None defScript = feeds.script() if not notdefault(defScript): defScript = None defPrio = feeds.priority() if not notdefault(defPrio): defPrio = None # Preparations, convert filters to regex's regexes = [] reTypes = [] reCats = [] rePPs = [] rePrios = [] reScripts = [] reEnabled = [] for filter in feeds.filters(): reCat = filter[0] if defCat in ('', '*'): reCat = None reCats.append(reCat) rePPs.append(filter[1]) reScripts.append(filter[2]) reTypes.append(filter[3]) if filter[3] in ('<', '>', 'F', 'S'): regexes.append(filter[4]) else: regexes.append(convert_filter(filter[4])) rePrios.append(filter[5]) reEnabled.append(filter[6] != '0') regcount = len(regexes) # Set first if this is the very first scan of this URI first = (feed not in self.jobs) and ignoreFirst # Add sabnzbd's custom User Agent feedparser.USER_AGENT = 'SABnzbd+/%s' % sabnzbd.version.__version__ # Read the RSS feed msg = None entries = None if readout: all_entries = [] for uri in uris: uri = uri.replace(' ', '%20') logging.debug("Running feedparser on %s", uri) feed_parsed = feedparser.parse(uri.replace('feed://', 'http://')) logging.debug("Done parsing %s", uri) if not feed_parsed: msg = T('Failed to retrieve RSS from %s: %s') % (uri, '?') logging.info(msg) status = feed_parsed.get('status', 999) if status in (401, 402, 403): msg = T('Do not have valid authentication for feed %s') % feed logging.info(msg) if status >= 500 and status <= 599: msg = T('Server side error (server code %s); could not get %s on %s') % (status, feed, uri) logging.info(msg) entries = feed_parsed.get('entries') if 'bozo_exception' in feed_parsed and not entries: msg = str(feed_parsed['bozo_exception']) if 'CERTIFICATE_VERIFY_FAILED' in msg: msg = T('Server %s uses an untrusted HTTPS certificate') % get_urlbase(uri) msg += ' - https://sabnzbd.org/certificate-errors' logging.error(msg) else: msg = T('Failed to retrieve RSS from %s: %s') % (uri, xml_name(msg)) logging.info(msg) if not entries: msg = T('RSS Feed %s was empty') % uri logging.info(msg) all_entries.extend(entries) entries = all_entries # In case of a new feed if feed not in self.jobs: self.jobs[feed] = {} jobs = self.jobs[feed] # Error in readout or now new readout if readout: if not entries: return unicoder(msg) else: entries = jobs.keys() # Filter out valid new links for entry in entries: if self.shutdown: return if readout: try: link, category, size, age, season, episode = _get_link(uri, entry) except (AttributeError, IndexError): link = None category = u'' size = 0L age = None logging.info(T('Incompatible feed') + ' ' + uri) logging.info("Traceback: ", exc_info=True) return T('Incompatible feed') title = entry.title # If there's multiple feeds, remove the duplicates based on title and size if len(uris) > 1: skip_job = False for job_link, job in jobs.items(): # Allow 5% size deviation because indexers might have small differences for same release if job.get('title') == title and link != job_link and (job.get('size')*0.95) < size < (job.get('size')*1.05): logging.info("Ignoring job %s from other feed", title) skip_job = True break if skip_job: continue else: link = entry category = jobs[link].get('orgcat', '') if category in ('', '*'): category = None title = jobs[link].get('title', '') size = jobs[link].get('size', 0L) age = jobs[link].get('age') season = jobs[link].get('season', 0) episode = jobs[link].get('episode', 0) if link: # Make sure spaces are quoted in the URL link = link.strip().replace(' ', '%20') newlinks.append(link) if link in jobs: jobstat = jobs[link].get('status', ' ')[0] else: jobstat = 'N' if jobstat in 'NGB' or (jobstat == 'X' and readout): # Match this title against all filters logging.debug('Trying title %s', title) result = False myCat = defCat myPP = defPP myScript = defScript myPrio = defPrio n = 0 if ('F' in reTypes or 'S' in reTypes) and (not season or not episode): season, episode = sabnzbd.newsunpack.analyse_show(title)[1:3] # Match against all filters until an positive or negative match logging.debug('Size %s', size) for n in xrange(regcount): if reEnabled[n]: if category and reTypes[n] == 'C': found = re.search(regexes[n], category) if not found: logging.debug("Filter rejected on rule %d", n) result = False break elif reTypes[n] == '<' and size and from_units(regexes[n]) < size: # "Size at most" : too large logging.debug('Filter rejected on rule %d', n) result = False break elif reTypes[n] == '>' and size and from_units(regexes[n]) > size: # "Size at least" : too small logging.debug('Filter rejected on rule %d', n) result = False break elif reTypes[n] == 'F' and not ep_match(season, episode, regexes[n]): # "Starting from SxxEyy", too early episode logging.debug('Filter requirement match on rule %d', n) result = False break elif reTypes[n] == 'S' and season and episode and ep_match(season, episode, regexes[n], title): logging.debug('Filter matched on rule %d', n) result = True break else: if regexes[n]: found = re.search(regexes[n], title) else: found = False if reTypes[n] == 'M' and not found: logging.debug("Filter rejected on rule %d", n) result = False break if found and reTypes[n] == 'A': logging.debug("Filter matched on rule %d", n) result = True break if found and reTypes[n] == 'R': logging.debug("Filter rejected on rule %d", n) result = False break if len(reCats): if not result and defCat: # Apply Feed-category on non-matched items myCat = defCat elif result and notdefault(reCats[n]): # Use the matched info myCat = reCats[n] elif category and not defCat: # No result and no Feed-category myCat = cat_convert(category) if myCat: myCat, catPP, catScript, catPrio = cat_to_opts(myCat) else: myCat = catPP = catScript = catPrio = None if notdefault(rePPs[n]): myPP = rePPs[n] elif not (reCats[n] or category): myPP = catPP if notdefault(reScripts[n]): myScript = reScripts[n] elif not (notdefault(reCats[n]) or category): myScript = catScript if rePrios[n] not in (str(DEFAULT_PRIORITY), ''): myPrio = rePrios[n] elif not ((rePrios[n] != str(DEFAULT_PRIORITY)) or category): myPrio = catPrio if cfg.no_dupes() and self.check_duplicate(title): if cfg.no_dupes() == 1: # Dupe-detection: Discard logging.info("Ignoring duplicate job %s", title) continue elif cfg.no_dupes() == 3: # Dupe-detection: Fail # We accept it so the Queue can send it to the History logging.info("Found duplicate job %s", title) else: # Dupe-detection: Pause myPrio = DUP_PRIORITY act = download and not first if link in jobs: act = act and not jobs[link].get('status', '').endswith('*') act = act or force star = first or jobs[link].get('status', '').endswith('*') else: star = first if result: _HandleLink(jobs, feed, link, title, size, age, season, episode, 'G', category, myCat, myPP, myScript, act, star, priority=myPrio, rule=str(n)) if act: new_downloads.append(title) else: _HandleLink(jobs, feed, link, title, size, age, season, episode, 'B', category, myCat, myPP, myScript, False, star, priority=myPrio, rule=str(n)) # Send email if wanted and not "forced" if new_downloads and cfg.email_rss() and not force: emailer.rss_mail(feed, new_downloads) remove_obsolete(jobs, newlinks) return msg def run(self): """ Run all the URI's and filters """ if not sabnzbd.PAUSED_ALL: active = False if self.next_run < time.time(): self.next_run = time.time() + cfg.rss_rate.get() * 60 feeds = config.get_rss() for feed in feeds.keys(): try: if feeds[feed].enable.get(): logging.info('Starting scheduled RSS read-out for "%s"', feed) active = True self.run_feed(feed, download=True, ignoreFirst=True) # Wait 15 seconds, else sites may get irritated for unused in xrange(15): if self.shutdown: return else: time.sleep(1.0) except KeyError: # Feed must have been deleted pass if active: self.save() logging.info('Finished scheduled RSS read-outs') @synchronized(LOCK) def show_result(self, feed): if feed in self.jobs: try: return self.jobs[feed] except: return {} else: return {} @synchronized(LOCK) def save(self): sabnzbd.save_admin(self.jobs, RSS_FILE_NAME) @synchronized(LOCK) def delete(self, feed): if feed in self.jobs: del self.jobs[feed] @synchronized(LOCK) def flag_downloaded(self, feed, fid): if feed in self.jobs: lst = self.jobs[feed] for link in lst: if lst[link].get('url', '') == fid: lst[link]['status'] = 'D' lst[link]['time_downloaded'] = time.localtime() @synchronized(LOCK) def lookup_url(self, feed, url): if url and feed in self.jobs: lst = self.jobs[feed] for link in lst: if lst[link].get('url') == url: return lst[link] return None @synchronized(LOCK) def clear_feed(self, feed): # Remove any previous references to this feed name, and start fresh if feed in self.jobs: del self.jobs[feed] @synchronized(LOCK) def clear_downloaded(self, feed): # Mark downloaded jobs, so that they won't be displayed any more. if feed in self.jobs: for item in self.jobs[feed]: if self.jobs[feed][item]['status'] == 'D': self.jobs[feed][item]['status'] = 'D-' def check_duplicate(self, title): """ Check if this title was in this or other feeds Return matching feed name """ title = title.lower() for fd in self.jobs: for lk in self.jobs[fd]: item = self.jobs[fd][lk] if item.get('status', ' ')[0] == 'D' and \ item.get('title', '').lower() == title: return fd return '' def _HandleLink(jobs, feed, link, title, size, age, season, episode, flag, orgcat, cat, pp, script, download, star, priority=NORMAL_PRIORITY, rule=0): """ Process one link """ if script == '': script = None if pp == '': pp = None jobs[link] = {} jobs[link]['title'] = title jobs[link]['url'] = link jobs[link]['cat'] = cat jobs[link]['pp'] = pp jobs[link]['script'] = script jobs[link]['prio'] = str(priority) jobs[link]['orgcat'] = orgcat jobs[link]['size'] = size jobs[link]['age'] = age jobs[link]['time'] = time.time() jobs[link]['rule'] = rule jobs[link]['season'] = season jobs[link]['episode'] = episode if special_rss_site(link): nzbname = None else: nzbname = title if download: jobs[link]['status'] = 'D' jobs[link]['time_downloaded'] = time.localtime() logging.info("Adding %s (%s) to queue", link, title) sabnzbd.add_url(link, pp=pp, script=script, cat=cat, priority=priority, nzbname=nzbname) else: if star: jobs[link]['status'] = flag + '*' else: jobs[link]['status'] = flag def _get_link(uri, entry): """ Retrieve the post link from this entry Returns (link, category, size) """ link = None category = '' size = 0L uri = uri.lower() age = datetime.datetime.now() # Try standard link and enclosures first link = entry.link if not link: link = entry.links[0].href if 'enclosures' in entry: try: link = entry.enclosures[0]['href'] size = int(entry.enclosures[0]['length']) except: pass if size == 0L: _RE_SIZE1 = re.compile(r'Size:\s*(\d+\.\d+\s*[KMG]{0,1})B\W*', re.I) _RE_SIZE2 = re.compile(r'\W*(\d+\.\d+\s*[KMG]{0,1})B\W*', re.I) # Try to find size in Description try: desc = entry.description.replace('\n', ' ').replace(' ', ' ') m = _RE_SIZE1.search(desc) or _RE_SIZE2.search(desc) if m: size = from_units(m.group(1)) except: pass # Try newznab attribute first, this is the correct one try: # Convert it to format that calc_age understands age = datetime.datetime(*entry['newznab']['usenetdate_parsed'][:6]) except: # Date from feed (usually lags behind) try: # Convert it to format that calc_age understands age = datetime.datetime(*entry.published_parsed[:6]) except: pass finally: # We need to convert it to local timezone, feedparser always returns UTC age = age - datetime.timedelta(seconds=time.timezone) # Maybe the newznab also provided SxxExx info try: season = re.findall('\d+', entry['newznab']['season'])[0] episode = re.findall('\d+', entry['newznab']['episode'])[0] except: season = episode = 0 if link and 'http' in link.lower(): try: category = entry.cattext except: try: category = entry.category except: try: # nzb.su category = entry.tags[0]['term'] except: try: category = entry.description except: category = '' return link, category, size, age, season, episode else: logging.warning(T('Empty RSS entry found (%s)'), link) return None, '', 0L, None, 0, 0 def special_rss_site(url): """ Return True if url describes an RSS site with odd titles """ return cfg.rss_filenames() or match_str(url, cfg.rss_odd_titles()) _RE_SP = re.compile(r's*(\d+)[ex](\d+)', re.I) def ep_match(season, episode, expr, title=None): """ Return True if season, episode is at or above expected Optionally `title` can be matched """ m = _RE_SP.search(expr) if m: # Make sure they are all integers for comparison req_season = int(m.group(1)) req_episode = int(m.group(2)) season = int_conv(season) episode = int_conv(episode) if season > req_season or (season == req_season and episode >= req_episode): if title: show = expr[:m.start()].replace('.', ' ').replace('_', ' ').strip() show = show.replace(' ', '[._ ]+') return bool(re.search(show, title, re.I)) else: return True else: return False else: return True SABnzbd-2.3.2/sabnzbd/sabtray.py0000644000000000000000000001410113217005257014570 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabtray.py - Systray icon for SABnzbd on Windows, contributed by Jan Schejbal """ import logging from time import sleep import sabnzbd from sabnzbd.panic import launch_a_browser import sabnzbd.api as api import sabnzbd.scheduler as scheduler from sabnzbd.downloader import Downloader import sabnzbd.cfg as cfg from sabnzbd.misc import to_units import os import cherrypy # contains the tray icon, which demands its own thread from sabnzbd.utils.systrayiconthread import SysTrayIconThread class SABTrayThread(SysTrayIconThread): sabicons = { 'default': 'icons/sabnzbd16_32.ico', 'green': 'icons/sabnzbd16_32green.ico', 'pause': 'icons/sabnzbd16_32paused.ico' } def __init__(self): # Wait for translated texts to be loaded while not sabnzbd.WEBUI_READY: sleep(0.2) logging.debug('language file not loaded, waiting') self.sabpaused = False self.counter = 0 text = "SABnzbd" self.set_texts() menu_options = ( (self.txt_show_int, None, self.browse), (self.txt_open_comp, None, self.opencomplete), (self.txt_trouble, None, ((self.txt_restart, None, self.restart), (self.txt_restart_nl, None, self.nologin), (self.txt_restart + ' - 127.0.0.1:8080', None, self.defhost))), (self.txt_pause + '/' + self.txt_resume, None, self.pauseresume), (self.txt_rss, None, self.rss), (self.txt_shutdown, None, self.shutdown), ) SysTrayIconThread.__init__(self, self.sabicons['default'], text, menu_options, None, 0, "SabTrayIcon") def set_texts(self): def fix(txt): if trans: return Tx(txt) else: return txt trans = str(get_codepage()) == str(sabnzbd.lang.CODEPAGE) self.txt_show_int = fix(TT('Show interface')) self.txt_open_comp = fix(TT('Open complete folder')) self.txt_trouble = fix(TT('Troubleshoot')) self.txt_pause = fix(TT('Pause')) self.txt_shutdown = fix(TT('Shutdown')) self.txt_resume = fix(TT('Resume')) self.txt_restart = fix(TT('Restart')) self.txt_restart_nl = fix(TT('Restart without login')) self.txt_idle = fix(TT('Idle')) self.txt_paused = fix(TT('Paused')) self.txt_remaining = fix(TT('Remaining')) self.txt_rss = fix(TT('Read all RSS feeds')) # called every few ms by SysTrayIconThread def doUpdates(self): """ Update menu info, once every 10 calls """ self.counter += 1 if self.counter > 10: self.sabpaused, bytes_left, bpsnow, time_left = api.fast_queue() mb_left = to_units(bytes_left) speed = to_units(bpsnow) if self.sabpaused: self.hover_text = self.txt_paused self.icon = self.sabicons['pause'] elif bytes_left > 0: self.hover_text = "%sB/s %s: %sB (%s)" % (speed, self.txt_remaining, mb_left, time_left) self.icon = self.sabicons['green'] else: self.hover_text = self.txt_idle self.icon = self.sabicons['default'] self.refresh_icon() self.counter = 0 # left-click handler def click(self, *args): # Make sure to stop the timer self.stop_click_timer() # Pause/resume and force update of icon/text self.pauseresume(None) self.counter = 11 # menu handler def opencomplete(self, icon): try: os.startfile(cfg.complete_dir.get_path()) except WindowsError: pass # menu handler def browse(self, icon): launch_a_browser(sabnzbd.BROWSER_URL, True) # menu handler def pauseresume(self, icon): if self.sabpaused: self.resume() else: self.pause() # menu handler def restart(self, icon): self.hover_text = self.txt_restart logging.info('Restart requested by tray') sabnzbd.trigger_restart() # menu handler def rss(self, icon): self.hover_text = self.txt_rss scheduler.force_rss() # menu handler def nologin(self, icon): sabnzbd.cfg.username.set('') sabnzbd.cfg.password.set('') sabnzbd.config.save_config() self.hover_text = self.txt_restart sabnzbd.trigger_restart() # menu handler def defhost(self, icon): sabnzbd.cfg.cherryhost.set('127.0.0.1') sabnzbd.cfg.enable_https.set(False) sabnzbd.config.save_config() self.hover_text = self.txt_restart sabnzbd.trigger_restart() # menu handler - adapted from interface.py def shutdown(self, icon): self.hover_text = self.txt_shutdown logging.info('Shutdown requested by tray') sabnzbd.halt() cherrypy.engine.exit() sabnzbd.SABSTOP = True # adapted from interface.py def pause(self): scheduler.plan_resume(0) Downloader.do.pause() # adapted from interface.py def resume(self): scheduler.plan_resume(0) sabnzbd.unpause_all() def get_codepage(): import locale _lang, code = locale.getlocale() logging.debug('SysTray uses codepage %s', code) return code SABnzbd-2.3.2/sabnzbd/sabtraylinux.py0000644000000000000000000001344413217005257015661 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.sabtraylinux - System tray icon for Linux, inspired from the Windows one """ import gtk import gobject import cherrypy from time import sleep import subprocess from threading import Thread import logging import sabnzbd from sabnzbd.panic import launch_a_browser import sabnzbd.api as api import sabnzbd.scheduler as scheduler from sabnzbd.downloader import Downloader import sabnzbd.cfg as cfg from sabnzbd.misc import to_units from sabnzbd.utils.upload import add_local class StatusIcon(Thread): sabicons = { 'default': 'icons/sabnzbd16_32.ico', 'green': 'icons/sabnzbd16_32green.ico', 'pause': 'icons/sabnzbd16_32paused.ico' } updatefreq = 1000 # ms def __init__(self): self.mythread = Thread(target=self.dowork) self.mythread.start() def dowork(self): # Wait for translated texts to be loaded while not sabnzbd.WEBUI_READY: sleep(0.2) logging.debug('language file not loaded, waiting') self.sabpaused = False self.statusicon = gtk.StatusIcon() self.icon = self.sabicons['default'] self.refresh_icon() self.tooltip = "SABnzbd" self.refresh_tooltip() self.statusicon.connect("popup-menu", self.right_click_event) gtk.gdk.threads_init() gtk.gdk.threads_enter() gobject.timeout_add(self.updatefreq, self.run) gtk.main() def refresh_icon(self): self.statusicon.set_from_file(self.icon) def refresh_tooltip(self): self.statusicon.set_tooltip(self.tooltip) # run this every updatefreq ms def run(self): self.sabpaused, bytes_left, bpsnow, time_left = api.fast_queue() mb_left = to_units(bytes_left) speed = to_units(bpsnow) if self.sabpaused: self.tooltip = T('Paused') self.icon = self.sabicons['pause'] elif bytes_left > 0: self.tooltip = "%sB/s %s: %sB (%s)" % (speed, T('Remaining'), mb_left, time_left) self.icon = self.sabicons['green'] else: self.tooltip = T('Idle') self.icon = self.sabicons['default'] self.refresh_icon() self.refresh_tooltip() return 1 def right_click_event(self, icon, button, time): """ menu """ menu = gtk.Menu() maddnzb = gtk.MenuItem(T("Add NZB")) mshowinterface = gtk.MenuItem(T("Show interface")) mopencomplete = gtk.MenuItem(T("Open complete folder")) mrss = gtk.MenuItem(T("Read all RSS feeds")) if self.sabpaused: mpauseresume = gtk.MenuItem(T("Resume")) else: mpauseresume = gtk.MenuItem(T("Pause")) mrestart = gtk.MenuItem(T("Restart")) mshutdown = gtk.MenuItem(T("Shutdown")) maddnzb.connect("activate", self.addnzb) mshowinterface.connect("activate", self.browse) mopencomplete.connect("activate", self.opencomplete) mrss.connect("activate", self.rss) mpauseresume.connect("activate", self.pauseresume) mrestart.connect("activate", self.restart) mshutdown.connect("activate", self.shutdown) menu.append(maddnzb) menu.append(mshowinterface) menu.append(mopencomplete) menu.append(mrss) menu.append(mpauseresume) menu.append(mrestart) menu.append(mshutdown) menu.show_all() menu.popup(None, None, gtk.status_icon_position_menu, button, time, self.statusicon) def addnzb(self, icon): """ menu handlers """ dialog = gtk.FileChooserDialog(title=None, action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_select_multiple(True) filter = gtk.FileFilter() filter.set_name("*.nbz,*.nbz.gz,*.bz2,*.zip,*.rar") filter.add_pattern("*.nzb*") filter.add_pattern("*.nzb.gz") filter.add_pattern("*.nzb.bz2") filter.add_pattern("*.zip") filter.add_pattern("*.rar") dialog.add_filter(filter) response = dialog.run() if response == gtk.RESPONSE_OK: for filename in dialog.get_filenames(): add_local(filename) dialog.destroy() def opencomplete(self, icon): subprocess.Popen(["xdg-open", cfg.complete_dir.get_path()]) def browse(self, icon): launch_a_browser(sabnzbd.BROWSER_URL, True) def pauseresume(self, icon): if self.sabpaused: self.resume() else: self.pause() def restart(self, icon): self.hover_text = T('Restart') sabnzbd.trigger_restart() def shutdown(self, icon): self.hover_text = T('Shutdown') sabnzbd.halt() cherrypy.engine.exit() sabnzbd.SABSTOP = True def pause(self): scheduler.plan_resume(0) Downloader.do.pause() def resume(self): scheduler.plan_resume(0) sabnzbd.unpause_all() def rss(self, icon): scheduler.force_rss() SABnzbd-2.3.2/sabnzbd/scheduler.py0000644000000000000000000004061413217005257015111 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.scheduler - Event Scheduler """ import random import logging import time import sabnzbd.utils.kronos as kronos import sabnzbd.rss as rss import sabnzbd.downloader import sabnzbd.dirscanner import sabnzbd.misc import sabnzbd.config as config import sabnzbd.cfg as cfg from sabnzbd.postproc import PostProcessor from sabnzbd.constants import LOW_PRIORITY, NORMAL_PRIORITY, HIGH_PRIORITY __SCHED = None # Global pointer to Scheduler instance SCHEDULE_GUARD_FLAG = False PP_PAUSE_EVENT = False def schedule_guard(): """ Set flag for scheduler restart """ global SCHEDULE_GUARD_FLAG SCHEDULE_GUARD_FLAG = True def pp_pause(): PostProcessor.do.paused = True def pp_resume(): PostProcessor.do.paused = False def pp_pause_event(): return PP_PAUSE_EVENT def init(): """ Create the scheduler and set all required events """ global __SCHED reset_guardian() __SCHED = kronos.ThreadedScheduler() rss_planned = False for schedule in cfg.schedules(): arguments = [] argument_list = None try: enabled, m, h, d, action_name = schedule.split() except: try: enabled, m, h, d, action_name, argument_list = schedule.split(None, 5) except: continue # Bad schedule, ignore if argument_list: arguments = argument_list.split() action_name = action_name.lower() try: m = int(m) h = int(h) except: logging.warning(T('Bad schedule %s at %s:%s'), action_name, m, h) continue if d.isdigit(): d = [int(i) for i in d] else: d = range(1, 8) if action_name == 'resume': action = scheduled_resume arguments = [] elif action_name == 'pause': action = sabnzbd.downloader.Downloader.do.pause arguments = [] elif action_name == 'pause_all': action = sabnzbd.pause_all arguments = [] elif action_name == 'shutdown': action = sabnzbd.shutdown_program arguments = [] elif action_name == 'restart': action = sabnzbd.restart_program arguments = [] elif action_name == 'pause_post': action = pp_pause elif action_name == 'resume_post': action = pp_resume elif action_name == 'speedlimit' and arguments != []: action = sabnzbd.downloader.Downloader.do.limit_speed elif action_name == 'enable_server' and arguments != []: action = sabnzbd.enable_server elif action_name == 'disable_server' and arguments != []: action = sabnzbd.disable_server elif action_name == 'scan_folder': action = sabnzbd.dirscanner.dirscan elif action_name == 'rss_scan': action = rss.run_method rss_planned = True elif action_name == 'remove_failed': action = sabnzbd.api.history_remove_failed elif action_name == 'remove_completed': action = sabnzbd.api.history_remove_completed elif action_name == 'enable_quota': action = sabnzbd.bpsmeter.BPSMeter.do.set_status arguments = [True] elif action_name == 'disable_quota': action = sabnzbd.bpsmeter.BPSMeter.do.set_status arguments = [False] elif action_name == 'pause_all_low': action = sabnzbd.nzbqueue.NzbQueue.do.pause_on_prio arguments = [LOW_PRIORITY] elif action_name == 'pause_all_normal': action = sabnzbd.nzbqueue.NzbQueue.do.pause_on_prio arguments = [NORMAL_PRIORITY] elif action_name == 'pause_all_high': action = sabnzbd.nzbqueue.NzbQueue.do.pause_on_prio arguments = [HIGH_PRIORITY] elif action_name == 'resume_all_low': action = sabnzbd.nzbqueue.NzbQueue.do.resume_on_prio arguments = [LOW_PRIORITY] elif action_name == 'resume_all_normal': action = sabnzbd.nzbqueue.NzbQueue.do.resume_on_prio arguments = [NORMAL_PRIORITY] elif action_name == 'resume_all_high': action = sabnzbd.nzbqueue.NzbQueue.do.resume_on_prio arguments = [HIGH_PRIORITY] elif action_name == 'pause_cat': action = sabnzbd.nzbqueue.NzbQueue.do.pause_on_cat arguments = [argument_list] elif action_name == 'resume_cat': action = sabnzbd.nzbqueue.NzbQueue.do.resume_on_cat arguments = [argument_list] else: logging.warning(T('Unknown action: %s'), action_name) continue if enabled == '1': logging.debug("Scheduling %s(%s) on days %s at %02d:%02d", action_name, arguments, d, h, m) __SCHED.add_daytime_task(action, action_name, d, None, (h, m), kronos.method.sequential, arguments, None) else: logging.debug("Skipping %s(%s) on days %s at %02d:%02d", action_name, arguments, d, h, m) # Set Guardian interval to 30 seconds __SCHED.add_interval_task(sched_guardian, "Guardian", 15, 30, kronos.method.sequential, None, None) # Set RSS check interval if not rss_planned: interval = cfg.rss_rate() delay = random.randint(0, interval - 1) logging.debug("Scheduling RSS interval task every %s min (delay=%s)", interval, delay) sabnzbd.rss.next_run(time.time() + delay * 60) __SCHED.add_interval_task(rss.run_method, "RSS", delay * 60, interval * 60, kronos.method.sequential, None, None) __SCHED.add_single_task(rss.run_method, 'RSS', 15, kronos.method.sequential, None, None) if cfg.version_check(): # Check for new release, once per week on random time m = random.randint(0, 59) h = random.randint(0, 23) d = (random.randint(1, 7), ) logging.debug("Scheduling VersionCheck on day %s at %s:%s", d[0], h, m) __SCHED.add_daytime_task(sabnzbd.misc.check_latest_version, 'VerCheck', d, None, (h, m), kronos.method.sequential, [], None) action, hour, minute = sabnzbd.bpsmeter.BPSMeter.do.get_quota() if action: logging.info('Setting schedule for quota check daily at %s:%s', hour, minute) __SCHED.add_daytime_task(action, 'quota_reset', range(1, 8), None, (hour, minute), kronos.method.sequential, [], None) if sabnzbd.misc.int_conv(cfg.history_retention()) > 0: logging.info('Setting schedule for midnight auto history-purge') __SCHED.add_daytime_task(sabnzbd.database.midnight_history_purge, 'midnight_history_purge', range(1, 8), None, (0, 0), kronos.method.sequential, [], None) logging.info('Setting schedule for midnight BPS reset') __SCHED.add_daytime_task(sabnzbd.bpsmeter.midnight_action, 'midnight_bps', range(1, 8), None, (0, 0), kronos.method.sequential, [], None) # Subscribe to special schedule changes cfg.rss_rate.callback(schedule_guard) def start(): """ Start the scheduler """ global __SCHED if __SCHED: logging.debug('Starting scheduler') __SCHED.start() def restart(force=False): """ Stop and start scheduler """ global __PARMS, SCHEDULE_GUARD_FLAG if force: SCHEDULE_GUARD_FLAG = True else: if SCHEDULE_GUARD_FLAG: SCHEDULE_GUARD_FLAG = False stop() analyse(sabnzbd.downloader.Downloader.do.paused) init() start() def stop(): """ Stop the scheduler, destroy instance """ global __SCHED if __SCHED: logging.debug('Stopping scheduler') try: __SCHED.stop() except IndexError: pass del __SCHED __SCHED = None def abort(): """ Emergency stop, just set the running attribute false """ global __SCHED if __SCHED: logging.debug('Terminating scheduler') __SCHED.running = False def sort_schedules(all_events, now=None): """ Sort the schedules, based on order of happening from now `all_events=True`: Return an event for each active day `all_events=False`: Return only first occurring event of the week `now` : for testing: simulated localtime() """ day_min = 24 * 60 week_min = 7 * day_min events = [] now = now or time.localtime() now_hm = now[3] * 60 + now[4] now = now[6] * day_min + now_hm for schedule in cfg.schedules(): parms = None try: # Note: the last parameter can have spaces (category name)! enabled, m, h, dd, action, parms = schedule.split(None, 5) except: try: enabled, m, h, dd, action = schedule.split(None, 4) except: continue # Bad schedule, ignore action = action.strip() if dd == '*': dd = '1234567' if not dd.isdigit(): continue # Bad schedule, ignore for d in dd: then = (int(d) - 1) * day_min + int(h) * 60 + int(m) dif = then - now if all_events and dif < 0: # Expired event will occur again after a week dif = dif + week_min events.append((dif, action, parms, schedule, enabled)) if not all_events: break events.sort(lambda x, y: x[0] - y[0]) return events def analyse(was_paused=False, priority=None): """ Determine what pause/resume state we would have now. 'priority': evaluate only effect for given priority, return True for paused """ global PP_PAUSE_EVENT PP_PAUSE_EVENT = False paused = None paused_all = False pause_post = False pause_low = pause_normal = pause_high = False speedlimit = None quota = True servers = {} for ev in sort_schedules(all_events=True): if priority is None: logging.debug('Schedule check result = %s', ev) # Skip if disabled if ev[4] == '0': continue action = ev[1] try: value = ev[2] except: value = None if action == 'pause': paused = True elif action == 'pause_all': paused_all = True PP_PAUSE_EVENT = True elif action == 'resume': paused = False paused_all = False elif action == 'pause_post': pause_post = True PP_PAUSE_EVENT = True elif action == 'resume_post': pause_post = False PP_PAUSE_EVENT = True elif action == 'speedlimit' and value is not None: speedlimit = ev[2] elif action == 'pause_all_low': pause_low = True elif action == 'pause_all_normal': pause_normal = True elif action == 'pause_all_high': pause_high = True elif action == 'resume_all_low': pause_low = False elif action == 'resume_all_normal': pause_normal = False elif action == 'resume_all_high': pause_high = False elif action == 'enable_quota': quota = True elif action == 'disable_quota': quota = False elif action == 'enable_server': try: servers[value] = 1 except: logging.warning(T('Schedule for non-existing server %s'), value) elif action == 'disable_server': try: servers[value] = 0 except: logging.warning(T('Schedule for non-existing server %s'), value) # Special case, a priority was passed, so evaluate only that and return state if priority == LOW_PRIORITY: return pause_low if priority == NORMAL_PRIORITY: return pause_normal if priority == HIGH_PRIORITY: return pause_high if priority is not None: return False # Normal analysis if not was_paused: if paused_all: sabnzbd.pause_all() else: sabnzbd.unpause_all() sabnzbd.downloader.Downloader.do.set_paused_state(paused or paused_all) PostProcessor.do.paused = pause_post if speedlimit is not None: sabnzbd.downloader.Downloader.do.limit_speed(speedlimit) sabnzbd.bpsmeter.BPSMeter.do.set_status(quota, action=False) for serv in servers: try: item = config.get_config('servers', serv) value = servers[serv] if bool(item.enable()) != bool(value): item.enable.set(value) sabnzbd.downloader.Downloader.do.init_server(serv, serv) except: pass config.save_config() # Support for single shot pause (=delayed resume) __PAUSE_END = None # Moment when pause will end def scheduled_resume(): """ Scheduled resume, only when no oneshot resume is active """ global __PAUSE_END if __PAUSE_END is None: sabnzbd.unpause_all() def __oneshot_resume(when): """ Called by delayed resume schedule Only resumes if call comes at the planned time """ global __PAUSE_END if __PAUSE_END is not None and (when > __PAUSE_END - 5) and (when < __PAUSE_END + 55): __PAUSE_END = None logging.debug('Resume after pause-interval') sabnzbd.unpause_all() else: logging.debug('Ignoring cancelled resume') def plan_resume(interval): """ Set a scheduled resume after the interval """ global __SCHED, __PAUSE_END if interval > 0: __PAUSE_END = time.time() + (interval * 60) logging.debug('Schedule resume at %s', __PAUSE_END) __SCHED.add_single_task(__oneshot_resume, '', interval * 60, kronos.method.sequential, [__PAUSE_END], None) sabnzbd.downloader.Downloader.do.pause() else: __PAUSE_END = None sabnzbd.unpause_all() def pause_int(): """ Return minutes:seconds until pause ends """ global __PAUSE_END if __PAUSE_END is None: return "0" else: val = __PAUSE_END - time.time() if val < 0: sign = '-' val = abs(val) else: sign = '' min = int(val / 60L) sec = int(val - min * 60) return "%s%d:%02d" % (sign, min, sec) def pause_check(): """ Unpause when time left is negative, compensate for missed schedule """ global __PAUSE_END if __PAUSE_END is not None and (__PAUSE_END - time.time()) < 0: __PAUSE_END = None logging.debug('Force resume, negative timer') sabnzbd.unpause_all() def plan_server(action, parms, interval): """ Plan to re-activate server after 'interval' minutes """ __SCHED.add_single_task(action, '', interval * 60, kronos.method.sequential, parms, None) def force_rss(): """ Add a one-time RSS scan, one second from now """ __SCHED.add_single_task(rss.run_method, 'RSS', 1, kronos.method.sequential, None, None) # Scheduler Guarding system # Each check sets the guardian flag False # Each successful scheduled check sets the flag # If 4 consecutive checks fail, the scheduler is assumed to have crashed __SCHED_GUARDIAN = False __SCHED_GUARDIAN_CNT = 0 def reset_guardian(): global __SCHED_GUARDIAN, __SCHED_GUARDIAN_CNT __SCHED_GUARDIAN = False __SCHED_GUARDIAN_CNT = 0 def sched_guardian(): global __SCHED_GUARDIAN, __SCHED_GUARDIAN_CNT __SCHED_GUARDIAN = True def sched_check(): global __SCHED_GUARDIAN, __SCHED_GUARDIAN_CNT if not __SCHED_GUARDIAN: __SCHED_GUARDIAN_CNT += 1 return __SCHED_GUARDIAN_CNT < 4 reset_guardian() return True SABnzbd-2.3.2/sabnzbd/skintext.py0000644000000000000000000017064613217005257015015 0ustar 00000000000000#!/usr/bin/python -OO # -*- coding: UTF-8 -*- # Copyright 2012-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.skintext - Language strings used in the templates """ SKIN_TEXT = { # Special texts 'stage-download' : TT('Download'), #: Queue status "download" 'stage-repair' : TT('Repair'), #: PP phase "repair" 'stage-filejoin' : TT('Join files'), #: PP phase "filejoin" 'stage-unpack' : TT('Unpack'), #: PP phase "unpack" 'stage-script' : TT('Script'), #: PP phase "script" 'stage-source' : TT('Source'), #: PP Source of the NZB (path or URL) 'stage-servers' : TT('Servers'), #: PP Distribution over servers 'stage-fail' : TT('Failure'), #: PP Failure message 'post-Completed' : TT('Completed'), #: PP status 'post-Failed' : TT('Failed'), #: PP status 'post-Queued' : TT('Waiting'), #: Queue and PP status 'post-Paused' : TT('Paused'), #: PP status 'post-Repairing' : TT('Repairing...'), #: PP status 'post-Extracting' : TT('Extracting...'), #: PP status 'post-Moving' : TT('Moving...'), #: PP status 'post-Running' : TT('Running script...'), #: PP status 'post-Fetching' : TT('Fetching extra blocks...'), #: PP status 'post-QuickCheck' : TT('Quick Check...'), #: PP status 'post-Verifying' : TT('Verifying...'), #: PP status 'post-Downloading' : TT('Downloading'), #: Pseudo-PP status, in reality used for Queue-status 'post-Propagating' : TT('Propagation delay'), 'post-Checking' : TT('Checking'), #: PP status 'sch-frequency' : TT('Frequency'), #: #: Config->Scheduler 'sch-action' : TT('Action'), #: #: Config->Scheduler 'sch-arguments' : TT('Arguments'), #: #: Config->Scheduler 'sch-task' : TT('Task'), #: #: Config->Scheduler 'sch-disable_server' : TT('disable server'), #: #: Config->Scheduler 'sch-enable_server' : TT('enable server'), #: #: Config->Scheduler 'sch-resume' : TT('Resume'), #: #: Config->Scheduler 'sch-pause' : TT('Pause'), #: #: Config->Scheduler 'sch-shutdown' : TT('Shutdown'), #: #: Config->Scheduler 'sch-restart' : TT('Restart'), #: #: Config->Scheduler 'sch-speedlimit' : TT('Speedlimit'), #: #: Config->Scheduler 'sch-pause_all' : TT('Pause All'), #: #: Config->Scheduler 'sch-pause_post' : TT('Pause post-processing'), #: #: Config->Scheduler 'sch-resume_post' : TT('Resume post-processing'), #: #: Config->Scheduler 'sch-scan_folder' : TT('Scan watched folder'), #: #: Config->Scheduler 'sch-rss_scan' : TT('Read RSS feeds'), #: #: Config->Scheduler 'sch-remove_failed' : TT('Remove failed jobs'), #: Config->Scheduler 'sch-remove_completed': TT('Remove completed jobs'), #: Config->Scheduler 'sch-pause_all_low' : TT('Pause low prioirty jobs'), #: Config->Scheduler 'sch-pause_all_normal':TT('Pause normal prioirty jobs'), #: Config->Scheduler 'sch-pause_all_high' : TT('Pause high prioirty jobs'), #: Config->Scheduler 'sch-resume_all_low' : TT('Resume low prioirty jobs'), #: Config->Scheduler 'sch-resume_all_normal':TT('Resume normal prioirty jobs'), #: Config->Scheduler 'sch-resume_all_high': TT('Resume high prioirty jobs'), #: Config->Scheduler 'sch-enable_quota' : TT('Enable quota management'), #: Config->Scheduler 'sch-disable_quota' : TT('Disable quota management'), #: Config->Scheduler 'sch-pause_cat' : TT('Pause jobs with category'), #: Config->Scheduler 'sch-resume_cat' : TT('Resume jobs with category'), #: Config->Scheduler 'prowl-off' : TT('Off'), #: Prowl priority 'prowl-very-low' : TT('Very Low'), #: Prowl priority 'prowl-moderate' : TT('Moderate'), #: Prowl priority 'prowl-normal' : TT('Normal'), #: Prowl priority 'prowl-high' : TT('High'), #: Prowl priority 'prowl-emergency' : TT('Emergency'), #: Prowl priority 'pushover-off' : TT('Off'), #: Prowl priority 'pushover-low' : TT('Low'), #: Prowl priority 'pushover-high' : TT('High'), #: Prowl priority # General texts 'default' : TT('Default'), #: Default value, used in dropdown menus 'none' : TT('None'), #: No value, used in dropdown menus 'MB' : TT('MB'), #: Megabytes 'GB' : TT('GB'), #: Gigabytes 'B' : TT('B'), #: Bytes (used as postfix, as in "GB", "TB") 'hour' : TT('hour'), #: One hour 'hours' : TT('hours'), #: Multiple hours 'minute' : TT('min'), #: One minute 'minutes' : TT('mins'), #: Multiple minutes 'second' : TT('sec'), #: One second 'seconds' : TT('seconds'), #: Multiple seconds 'day' : TT('day'), 'days' : TT('days'), 'week' : TT('week'), 'month' : TT('Month'), 'year' : TT('Year'), 'January': TT('January'), 'February': TT('February'), 'March': TT('March'), 'April': TT('April'), 'May': TT('May'), 'June': TT('June'), 'July': TT('July'), 'August': TT('August'), 'September': TT('September'), 'October': TT('October'), 'November': TT('November'), 'December': TT('December'), 'monday' : TT('Monday'), 'tuesday' : TT('Tuesday'), 'wednesday' : TT('Wednesday'), 'thursday' : TT('Thursday'), 'friday' : TT('Friday'), 'saturday' : TT('Saturday'), 'sunday' : TT('Sunday'), 'day-of-month' : TT('Day of month'), 'thisWeek' : TT('This week'), 'thisMonth' : TT('This month'), 'today' : TT('Today'), 'total' : TT('Total'), 'on' : TT('on'), 'off' : TT('off'), 'parameters' : TT('Parameters'), #: Config: startup parameters of SABnzbd 'pythonVersion' : TT('Python Version'), 'notAvailable' : TT('Not available'), 'homePage' : TT('Home page'), #: Home page of the SABnzbd project 'source' : TT('Source'), #: Where to find the SABnzbd sourcecode 'or' : TT('or'), #: Used in "IRC or IRC-Webaccess" 'host' : TT('Host'), 'comment' : TT('Comment'), 'send' : TT('Send'), 'cancel' : TT('Cancel'), 'other' : TT('Other'), 'report' : TT('Report'), 'video' : TT('Video'), 'audio' : TT('Audio'), 'notUsed' : TT('Not used'), 'orLess' : TT('or less'), 'login' : TT('Log in'), 'logout' : TT('Log out'), 'rememberme' : TT('Remember me'), # General template elements 'signOn' : TT('The automatic usenet download tool'), #: SABnzbd's theme line 'button-save' : TT('Save'), #: "Save" button 'confirm' : TT('Are you sure?'), #: Used in confirmation popups 'delFiles' : TT('Delete all downloaded files?'), #: Used in confirmation popups # Header 'menu-home' : TT('Home'), #: Main menu item 'menu-queue' : TT('Queue'), #: Main menu item 'menu-history' : TT('History'), #: Main menu item 'menu-config' : TT('Config'), #: Main menu item 'menu-cons' : TT('Status'), #: Main menu item 'menu-help' : TT('Help'), #: Main menu item 'menu-wiki' : TT('Wiki'), #: Main menu item 'menu-forums' : TT('Forum'), #: Main menu item 'menu-irc' : TT('IRC'), #: Main menu item 'menu-issues' : TT('Issues'), #: Main menu item 'menu-donate' : TT('Support the project, Donate!'), #: Main menu item 'cmenu-general' : TT('General'), #: Main menu item 'cmenu-folders' : TT('Folders'), #: Main menu item 'cmenu-switches' : TT('Switches'), #: Main menu item 'cmenu-servers' : TT('Servers'), #: Main menu item 'cmenu-scheduling' : TT('Scheduling'), #: Main menu item 'cmenu-rss' : TT('RSS'), #: Main menu item 'cmenu-notif' : TT('Notifications'), #: Main menu item 'cmenu-email' : TT('Email'), #: Main menu item 'cmenu-cat' : TT('Categories'), #: Main menu item 'cmenu-sorting' : TT('Sorting'), #: Main menu item 'cmenu-special' : TT('Special'), #: Main menu item 'cmenu-search' : TT('Search'), #: Main menu item # Footer 'ft-download' : TT('Download Dir'), # Used in Footer 'ft-paused' : TT('PAUSED'), # Used in Footer 'ft-buffer@2' : TT('Cached %s articles (%s)'), # Used in Footer 'ft-sysload' : TT('Sysload'), # Used in Footer 'ft-newRelease@1' : TT('New release %s available at'), # Used in Footer # Main page 'shutdownOK?' : TT('Are you sure you want to shutdown SABnzbd?'), 'link-shutdown' : TT('Shutdown'), #: Shutdown SABnzbd 'link-pause' : TT('Pause'), #: Pause downloading 'link-resume' : TT('Resume'), #: Resume downloading 'button-add' : TT('Add'), #: Add NZB to queue (button) 'add' : TT('Add'), #: Add NZB to queue (header) 'addFile' : TT('Add File'), #: Add NZB file to queue (header 'category' : TT('Category'), #: Job category 'pp' : TT('Processing'), 'script' : TT('Script'), 'priority' : TT('Priority'), 'pp-none' : TT('Download'), #: Post processing pick list 'pp-repair' : TT('+Repair'), #: Post processing pick list 'pp-unpack' : TT('+Unpack'), #: Post processing pick list 'pp-delete' : TT('+Delete'), #: Post processing pick list 'pp-r' : TT('R'), #: Post processing pick list: abbreviation for "+Repair" 'pp-u' : TT('U'), #: Post processing pick list: abbreviation for "+Unpack" 'pp-d' : TT('D'), #: Post processing pick list: abbreviation for "+Delete" 'pr-force' : TT('Force'), #: Priority pick list 'pr-normal' : TT('Normal'), #: Priority pick list 'pr-high' : TT('High'), #: Priority pick list 'pr-low' : TT('Low'), #: Priority pick list 'pr-paused' : TT('Paused'), #: Priority pick list 'pr-stop' : TT('Stop'), #: Priority pick list 'enterURL' : TT('Enter URL'), #: Add NZB Dialog # Queue page 'onQueueFinish' : TT('On queue finish'), #: Queue page selection menu 'shutdownPc' : TT('Shutdown PC'), #: Queue page end-of-queue action 'standbyPc' : TT('Standby PC'), #: Queue page end-of-queue action 'hibernatePc' : TT('Hibernate PC'), #: Queue page end-of-queue action 'shutdownSab' : TT('Shutdown SABnzbd'), #: Queue page end-of-queue action 'speedLimit' : TT('Speed Limit'), #: Queue page selection menu or entry box 'pauseFor' : TT('Pause for'), #: Queue page button or entry box 'mode' : TT('Processing'), #: Queue page table column header 'order' : TT('Order'), #: Queue page table column header 'name' : TT('Name'), #: Queue page table column header 'eta' : TT('ETA'), #: Queue page table column header, "estimated time of arrival" 'age' : TT('AGE'), #: Queue page table column header, "age of the NZB" 'button-del' : TT('Del'), #: Queue page table, "Delete" button 'button-retry' : TT('Retry'), #: Queue page button 'eoq-actions' : TT('Actions'), #: Queue end-of-queue selection box 'eoq-scripts' : TT('Scripts'), #: Queue page table, script selection menu 'purgeQueue' : TT('Purge Queue'), #: Queue page button 'purgeQueueConf' : TT('Delete all items from the queue?'), #: Confirmation popup 'purgeNZBs' : TT('Purge NZBs'), #: Queue page button 'purgeNZBs-Files' : TT('Purge NZBs & Delete Files'), #: Queue page button 'retryQueue' : TT('Retry all failed jobs'), #: Retry all failed jobs dialog box 'removeNZB' : TT('Remove NZB'), #: Queue page button 'removeNZB-Files' : TT('Remove NZB & Delete Files'), #: Queue page button 'AofB' : TT('of'), #: Queue page, as in "4G *of* 10G" 'missingArt': TT('Missing articles'), #: Caption for missing articles in Queue 'quota-left' : TT('Quota left'), #: Remaining quota (displayed in Queue) 'manual' : TT('manual'), #: Manual reset of quota 'link-resetQuota' : TT('Reset Quota now'), # History page 'purgeHist' : TT('Purge History'), #: History page button 'purgeHistConf' : TT('Delete all completed items from History?'), #: Confirmation popup 'hideDetails' : TT('Hide details'), #: Button/link hiding History job details 'showDetails' : TT('Show details'), #: Button/link showing History job details 'showFailedHis' : TT('Show Failed'), #: Button or link showing only failed History jobs. DON'T MAKE THIS VERY LONG! 'showAllHis' : TT('Show All'), #: Button or link showing all History jobs 'completed' : TT('Completed'), #: History: job status 'size' : TT('Size'), #: History table header 'status' : TT('Status'), #: History table header 'purgeFailed' : TT('Purge Failed NZBs'), #: Button to delete all failed jobs in History 'purgeFailed-Files' : TT('Purge Failed NZBs & Delete Files'), #: Button to delete all failed jobs in History, including files 'purgeCompl' : TT('Purge Completed NZBs'), #: Button to delete all completed jobs in History 'purgePage' : TT('Purge NZBs on the current page'), #: Button to delete jobs on current page in History 'opt-extra-NZB' : TT('Optional Supplemental NZB'), #: Button to add NZB to failed job in History 'msg-path' : TT('Path'), #: Path as displayed in History details 'link-retryAll' : TT('Retry all failed'), #: Retry all failed jobs in History 'retryNZBs' : TT('Retry All'), #: Retry all button for Retry All Failed Jobs 'spam' : TT('Virus/spam'), 'encrypted' : TT('Passworded'), 'expired' : TT('Out of retention'), 'otherProblem' : TT('Other problem'), # Connections page 'link-forceDisc' : TT('Force Disconnect'), #: Status page button 'askTestEmail' : TT('This will send a test email to your account.'), 'link-showLog' : TT('Show Logging'), #: Status page button 'link-testEmail' : TT('Test Email'), #: Status page button 'logging' : TT('Logging'), #: Status page selection menu 'log-errWarn' : TT('Errors/Warning'), #: Status page table header 'log-info' : TT('+ Info'), #: Status page logging selection value 'log-debug' : TT('+ Debug'), #: Status page logging selection value 'connections' : TT('Connections'), #: Status page tab header 'lastWarnings' : TT('Latest Warnings'), #: Status page, table header 'clearWarnings' : TT('clear'), #: Status page button 'server-blocked' : TT('Unblock'), #: Status page button 'article-id' : TT('Article identifier'), #: Status page, article identifier 'file-set' : TT('File set'), #: Status page, par-set that article belongs to 'warn-when' : TT('When'), #: Status page, table column header, when error occured 'warn-type' : TT('Type'), #: Status page, table column header, type of message 'warning' : TT('Warning'), #: Status page, table column header, actual message 'warnings' : TT('Warnings'), #: Footer: indicator of warnings 'enabled' : TT('Enabled'), #: Status page, indicator that server is enabled # Dashboard 'dashboard-title' : TT('Dashboard'), 'dashboard-connectionError' : TT('Connection failed!'), 'dashboard-localIP4' : TT('Local IPv4 address'), 'dashboard-publicIP4' : TT('Public IPv4 address'), 'dashboard-IP6' : TT('IPv6 address'), 'dashboard-NameserverDNS' : TT('Nameserver / DNS Lookup'), 'dashboard-cpuModel' : TT('CPU Model'), 'dashboard-systemPerformance' : TT('System Performance (Pystone)'), #: Do not translate Pystone 'dashboard-downloadDirSpeed' : TT('Download folder speed'), 'dashboard-completeDirSpeed' : TT('Complete folder speed'), 'dashboard-writingSpeed' : TT('Writing speed'), 'dashboard-speedTestFailed' : TT('Could not write. Check that the directory is writable.'), 'dashboard-clickToStart' : TT('Click on Repeat test button below to determine'), 'dashboard-repeatTest' : TT('Repeat test'), # Configuration 'confgFile' : TT('Config File'), 'cache' : TT('Used cache'), #: Main config page, how much cache is in use 'explain-Restart' : TT('This will restart SABnzbd.
Use it when you think the program has a stability problem.
Downloading will be paused before the restart and resume afterwards.'), 'explain-needNewLogin' : TT('
If authentication is enabled, you will need to login again.'), 'button-advanced' : TT('Advanced'), 'button-restart' : TT('Restart'), 'explain-orphans' : TT('There are orphaned jobs in the download folder.
You can choose to delete them (including files) or send them back to the queue.'), 'button-repair' : TT('Repair'), 'explain-Repair' : TT('The "Repair" button will restart SABnzbd and do a complete
reconstruction of the queue content, preserving already downloaded files.
This will modify the queue order.'), 'confirmWithoutSavingPrompt' : TT('Changes have not been saved, and will be lost.'), 'explain-sessionExpire': TT('When your IP address changes or SABnzbd is restarted the session will expire.'), #'explain-Shutdown' : TT('This will end the SABnzbd process.
You will be unable to access SABnzbd and no downloading will take place until the service is started again.'), 'opt-enable_unzip' : TT('Enable Unzip'), 'opt-enable_7zip' : TT('Enable 7zip'), 'opt-multicore-par2' : TT('Multicore Par2'), 'explain-nosslcontext' : TT('Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will be encrypted, however, validating a server\'s identity using its certificates is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-date local CA certificates are required.'), 'explain-getpar2mt': TT('Speed up repairs by installing multicore Par2, it is available for many platforms.'), 'version' : TT('Version'), 'uptime' : TT('Uptime'), 'backup' : TT('Backup'), #: Indicates that server is Backup server in Status page 'readwiki': TT('Read the Wiki Help on this!'), 'restarting-sab': TT('Restarting SABnzbd...'), # Config->General 'restartRequired' : TT('Changes will require a SABnzbd restart!'), 'webServer' : TT('SABnzbd Web Server'), 'opt-host' : TT('SABnzbd Host'), 'explain-host' : TT('Host SABnzbd should listen on.'), 'opt-port' : TT('SABnzbd Port'), 'explain-port' : TT('Port SABnzbd should listen on.'), 'opt-web_dir' : TT('Web Interface'), 'explain-web_dir' : TT('Choose a skin.'), 'opt-web_username' : TT('SABnzbd Username'), 'explain-web_username' : TT('Optional authentication username.'), 'opt-web_password' : TT('SABnzbd Password'), 'explain-web_password' : TT('Optional authentication password.'), 'checkSafety' : TT('If the SABnzbd Host or Port is exposed to the internet, your current settings allow full external access to the SABnzbd interface.'), 'security' : TT('Security'), 'opt-enable_https' : TT('Enable HTTPS'), 'opt-notInstalled' : TT('not installed'), 'explain-enable_https' : TT('Enable accessing the interface from a HTTPS address.'), 'opt-https_port' : TT('HTTPS Port'), 'explain-https_port' : TT('If empty, the standard port will only listen to HTTPS.'), 'opt-https_cert' : TT('HTTPS Certificate'), 'explain-https_cert' : TT('File name or path to HTTPS Certificate.'), 'explain-new-cert': TT('Generate new self-signed certificate and key. Requires SABnzbd restart!'), 'opt-https_key' : TT('HTTPS Key'), 'explain-https_key' : TT('File name or path to HTTPS Key.'), 'opt-https_chain' : TT('HTTPS Chain Certifcates'), 'explain-https_chain' : TT('File name or path to HTTPS Chain.'), 'tuning' : TT('Tuning'), 'opt-rss_rate' : TT('RSS Checking Interval'), 'explain-rss_rate' : TT('Checking interval (in minutes, at least 15). Not active when you use the Scheduler!'), 'opt-bandwidth_max' : TT('Maximum line speed'), 'opt-bandwidth_perc' : TT('Percentage of line speed'), 'explain-bandwidth_perc' : TT('Which percentage of the linespeed should SABnzbd use, e.g. 50'), 'opt-cache_limitstr' : TT('Article Cache Limit'), 'explain-cache_limitstr' : TT('Cache articles in memory to reduce disk access.
In bytes, optionally follow with K,M,G. For example: "64M" or "128M"'), 'opt-cleanup_list' : TT('Cleanup List'), 'explain-cleanup_list' : TT('List of file extensions that should be deleted after download.
For example: nfo or nfo, sfv'), 'opt-history_retention' : TT('History Retention'), 'explain-history_retention' : TT('Automatically delete completed jobs from History. Beware that Duplicate Detection and some external tools rely on History information.'), 'history_retention-all' : TT('Keep all jobs'), 'history_retention-number' : TT('Keep maximum number of completed jobs'), 'history_retention-days' : TT('Keep completed jobs maximum number of days'), 'history_retention-none' : TT('Do not keep any completed jobs'), 'history_retention-limit': TT('Jobs'), 'button-saveChanges' : TT('Save Changes'), 'button-restoreDefaults' : TT('Restore Defaults'), 'explain-restoreDefaults' : TT('Reset'), 'opt-language' : TT('Language'), 'explain-language' : TT('Select a web interface language.'), 'explain-ask-language': TT('Help us translate SABnzbd in your language!
Add untranslated texts or improved existing translations here:'), # Link to sabnzbd.org follows this text 'opt-apikey' : TT('API Key'), 'explain-apikey' : TT('This key will give 3rd party programs full access to SABnzbd.'), 'opt-nzbkey' : TT('NZB Key'), 'explain-nzbkey' : TT('This key will allow 3rd party programs to add NZBs to SABnzbd.'), 'button-apikey' : TT('Generate New Key'), 'explain-qr-code' : TT('API Key QR Code'), #: Explanation for QR code of APIKEY 'opt-local_ranges' : TT('List of local network ranges'), 'explain-local_ranges' : TT('All local network addresses start with these prefixes (often "192.168.1.")'), 'opt-inet_exposure' : TT('External internet access'), 'explain-inet_exposure' : TT('You can set access rights for systems outside your local network. Requires List of local network ranges to be defined.'), 'inet-local' : TT('No access'), # Selection value for external access 'inet-nzb' : TT('Add NZB files '), # Selection value for external access 'inet-api' : TT('API (no Config)'), # Selection value for external access 'inet-fullapi' : TT('Full API'), # Selection value for external access 'inet-ui' : TT('Full Web interface'), # Selection value for external access 'inet-external_login' : TT('Only external access requires login'), # Selection value for external access # Config->Folders 'explain-folderConfig' : TT('NOTE: Folders will be created automatically when Saving. You may use absolute paths to save outside of the default folders.'), 'userFolders' : TT('User Folders'), 'browse-folder' : TT('Browse'), 'in' : TT('In'), 'opt-download_dir' : TT('Temporary Download Folder'), 'explain-download_dir' : TT('Location to store unprocessed downloads.
Can only be changed when queue is empty.'), 'opt-download_free' : TT('Minimum Free Space for Temporary Download Folder'), 'explain-download_free' : TT('Auto-pause when free space is beneath this value.
In bytes, optionally follow with K,M,G,T. For example: "800M" or "8G"'), 'opt-complete_dir' : TT('Completed Download Folder'), 'explain-complete_dir' : TT('Location to store finished, fully processed downloads.
Can be overruled by user-defined categories.'), 'opt-permissions' : TT('Permissions for completed downloads'), 'explain-permissions' : TT('Set permissions pattern for completed files/folders.
In octal notation. For example: "755" or "777"'), 'opt-dirscan_dir' : TT('Watched Folder'), 'explain-dirscan_dir' : TT('Folder to monitor for .nzb files.
Also scans .zip .rar and .tar.gz archives for .nzb files.'), 'opt-dirscan_speed' : TT('Watched Folder Scan Speed'), 'explain-dirscan_speed' : TT('Number of seconds between scans for .nzb files.'), 'opt-script_dir' : TT('Scripts Folder'), 'explain-script_dir' : TT('Folder containing user scripts.'), 'opt-email_dir' : TT('Email Templates Folder'), 'explain-email_dir' : TT('Folder containing user-defined email templates.'), 'opt-password_file' : TT('Password file'), 'explain-password_file' : TT('File containing all passwords to be tried on encrypted RAR files.'), 'systemFolders' : TT('System Folders'), 'opt-admin_dir' : TT('Administrative Folder'), 'explain-admin_dir1' : TT('Location for queue admin and history database.
Can only be changed when queue is empty.'), 'explain-admin_dir2' : TT('Data will not be moved. Requires SABnzbd restart!'), 'opt-log_dir' : TT('Log Folder'), 'explain-log_dir' : TT('Location of log files for SABnzbd.
Requires SABnzbd restart!'), 'opt-nzb_backup_dir' : TT('.nzb Backup Folder'), 'explain-nzb_backup_dir' : TT('Location where .nzb files will be stored.'), 'base-folder' : TT('Default Base Folder'), # Config->Switches 'opt-enable_all_par' : TT('Download all par2 files'), 'explain-enable_all_par' : TT('This prevents multiple repair runs by downloading all par2 files when needed.'), 'opt-enable_recursive' : TT('Enable recursive unpacking'), 'explain-enable_recursive' : TT('Unpack archives (rar, zip, 7z) within archives.'), 'opt-flat_unpack' : TT('Ignore any folders inside archives'), 'explain-flat_unpack' : TT('All files will go into a single folder.'), 'opt-top_only' : TT('Only Get Articles for Top of Queue'), 'explain-top_only' : TT('Enable for less memory usage. Disable to prevent slow jobs from blocking the queue.'), 'opt-safe_postproc' : TT('Post-Process Only Verified Jobs'), 'explain-safe_postproc' : TT('Only perform post-processing on jobs that passed all PAR2 checks.'), 'opt-pause_on_pwrar' : TT('Action when encrypted RAR is downloaded'), 'explain-pause_on_pwrar' : TT('In case of "Pause", you\'ll need to set a password and resume the job.'), 'opt-no_dupes' : TT('Detect Duplicate Downloads'), 'explain-no_dupes' : TT('Detect identical NZB files (based on items in your History or files in .nzb Backup Folder)'), 'opt-no_series_dupes' : TT('Detect duplicate episodes in series'), 'explain-no_series_dupes' : TT('Detect identical episodes in series (based on "name/season/episode" of items in your History)'), 'opt-series_propercheck' : TT('Allow proper releases'), 'explain-series_propercheck' : TT('Bypass series duplicate detection if PROPER, REAL or REPACK is detected in the download name'), 'nodupes-off' : TT('Off'), #: Three way switch for duplicates 'nodupes-ignore' : TT('Discard'), #: Four way switch for duplicates 'nodupes-pause' : TT('Pause'), #: Four way switch for duplicates 'nodupes-fail' : TT('Fail job (move to History)'), #: Four way switch for duplicates 'nodupes-tag' : TT('Tag job'), #: Four way switch for duplicates 'abort' : TT('Abort'), #: Three way switch for encrypted posts 'opt-action_on_unwanted_extensions' : TT('Action when unwanted extension detected'), 'explain-action_on_unwanted_extensions' : TT('Action when an unwanted extension is detected in RAR files'), 'opt-unwanted_extensions' : TT('Unwanted extensions'), 'explain-unwanted_extensions' : TT('List all unwanted extensions. For example: exe or exe, com'), 'opt-sfv_check' : TT('Enable SFV-based checks'), 'explain-sfv_check' : TT('Do an extra verification based on SFV files.'), 'opt-script_can_fail' : TT('User script can flag job as failed'), 'explain-script_can_fail' : TT('When the user script returns a non-zero exit code, the job will be flagged as failed.'), 'opt-new_nzb_on_failure' : TT('On failure, try alternative NZB'), 'explain-new_nzb_on_failure' : TT('Some servers provide an alternative NZB when a download fails.'), 'opt-enable_meta' : TT('Use tags from indexer'), 'explain-enable_meta' : TT('When sorting, use tags from indexer for title, season, episode, etc. Otherwise all naming is derived from the NZB name.'), 'opt-folder_rename' : TT('Enable folder rename'), 'explain-folder_rename' : TT('Use temporary names during post processing. Disable when your system doesn\'t handle that properly.'), 'opt-pre_script' : TT('Pre-queue user script'), 'explain-pre_script' : TT('Used before an NZB enters the queue.'), 'opt-par_option' : TT('Extra PAR2 Parameters'), 'explain-par_option' : TT('Read the Wiki Help on this!'), 'opt-nice' : TT('Nice Parameters'), 'explain-nice' : TT('Read the Wiki Help on this!'), 'opt-ionice' : TT('IONice Parameters'), 'explain-ionice' : TT('Read the Wiki Help on this!'), 'opt-auto_disconnect' : TT('Disconnect on Empty Queue'), 'explain-auto_disconnect' : TT('Disconnect from Usenet server(s) when queue is empty or paused.'), 'opt-auto_sort' : TT('Sort by Age'), 'explain-auto_sort' : TT('Automatically sort items by (average) age.'), 'opt-direct_unpack' : TT('Direct Unpack'), 'explain-direct_unpack' : TT('Jobs will start unpacking during the downloading to reduce post-processing time. Only works for jobs that do not need repair.'), 'opt-propagation_delay' : TT('Propagation delay'), 'explain-propagation_delay' : TT('Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay.'), 'opt-check_new_rel' : TT('Check for New Release'), 'explain-check_new_rel' : TT('Weekly check for new SABnzbd release.'), 'also-test' : TT('Also test releases'), #: Pick list for weekly test for new releases 'opt-replace_spaces' : TT('Replace Spaces in Foldername'), 'explain-replace_spaces' : TT('Replace spaces with underscores in folder names.'), 'opt-replace_dots' : TT('Replace dots in Foldername'), 'explain-replace_dots' : TT('Replace dots with spaces in folder names.'), 'opt-sanitize_safe' : TT('Make Windows compatible'), 'explain-sanitize_safe' : TT('For servers: make sure names are compatible with Windows.'), 'opt-auto_browser' : TT('Launch Browser on Startup'), 'explain-auto_browser' : TT('Launch the default web browser when starting SABnzbd.'), 'opt-pause_on_post_processing' : TT('Pause Downloading During Post-Processing'), 'explain-pause_on_post_processing' : TT('Pauses downloading at the start of post processing and resumes when finished.'), 'opt-ignore_samples' : TT('Ignore Samples'), 'explain-ignore_samples' : TT('Filter out sample files (e.g. video samples).'), 'igsam-del' : TT('Delete after download'), 'opt-enable_https_verification' : TT('HTTPS certificate verification'), 'explain-enable_https_verification' : TT('Verify certificates when connecting to indexers and RSS-sources using HTTPS.'), 'swtag-server' : TT('Server'), 'swtag-queue' : TT('Queue'), 'swtag-pp' : TT('Post processing'), 'swtag-naming' : TT('Naming'), 'swtag-quota' : TT('Quota'), 'swtag-indexing' : TT('Indexing'), 'opt-quota_size' : TT('Size'), #: Size of the download quota 'explain-quota_size' : TT('How much can be downloaded this month (K/M/G)'), 'opt-quota_day' : TT('Reset day'), #: Reset day of the download quota 'explain-quota_day' : TT('On which day of the month or week (1=Monday) does your ISP reset the quota? (Optionally with hh:mm)'), 'opt-quota_resume' : TT('Auto resume'), #: Auto-resume download on the reset day 'explain-quota_resume' : TT('Should downloading resume after the quota is reset?'), 'opt-quota_period' : TT('Quota period'), #: Does the quota get reset every day, week or month? 'explain-quota_period' : TT('Does the quota get reset each day, week or month?'), 'opt-pre_check' : TT('Check before download'), 'explain-pre_check' : TT('Try to predict successful completion before actual download (slower!)'), 'opt-ssl_ciphers' : TT('SSL Ciphers'), 'explain-ssl_ciphers' : TT('Increase performance by forcing a lower SSL encryption strength.'), 'opt-max_art_tries' : TT('Maximum retries'), 'explain-max_art_tries' : TT('Maximum number of retries per server'), 'opt-fail_hopeless_jobs' : TT('Abort jobs that cannot be completed'), 'explain-fail_hopeless_jobs' : TT('When during download it becomes clear that too much data is missing, abort the job'), 'opt-rating_enable' : TT('Enable Indexer Integration'), 'explain-rating_enable' : TT('Indexers can supply rating information when a job is added and SABnzbd can report to the indexer if a job couldn\'t be completed.'), 'opt-rating_api_key' : TT('API Key'), 'explain-rating_api_key' : TT('This key provides identity to indexer. Check your profile on the indexer\'s website.'), 'opt-rating_filter_enable' : TT('Enable Filtering'), 'explain-rating_filter_enable' : TT('Action downloads according to filtering rules.'), 'opt-rating_filter_abort_if' : TT('Abort If'), 'opt-rating_filter_pause_if' : TT('Else Pause If'), 'opt-rating_filter_video' : TT('Video rating'), 'opt-rating_filter_audio' : TT('Audio rating'), 'opt-rating_filter_passworded' : TT('Passworded'), 'opt-rating_filter_spam' : TT('Spam'), 'opt-rating_filter_confirmed' : TT('Confirmed'), 'opt-rating_filter_downvoted' : TT('More thumbs down than up'), 'opt-rating_filter_keywords' : TT('Title keywords'), 'explain-rating_filter_keywords' : TT('Comma separated list'), 'opt-load_balancing' : TT('Server load-balancing'), 'no-load-balancing' : TT('Prevent load-balancing'), 'load-balancing' : TT('Allow load-balancing'), 'load-balancing-happy-eyeballs' : TT('Allow load-balancing with optimization for IPv6'), 'explain-load_balancing' : TT('Useful if a newsserver has more than one IPv4/IPv6 address'), # Config->Server 'addServer' : TT('Add Server'), #: Caption 'srv-displayname' : TT('Server description'), #: User defined name for server 'srv-host' : TT('Host'), #: Server hostname or IP 'srv-port' : TT('Port'), #: Server port 'srv-username' : TT('Username'), #: Server username 'srv-password' : TT('Password'), #: Server password 'srv-timeout' : TT('Timeout'), #: Server timeout 'srv-connections' : TT('Connections'), #: Server: amount of connections 'srv-retention' : TT('Retention time'), #: Server's retention time in days 'srv-ssl' : TT('SSL'), #: Server SSL tickbox 'explain-ssl' : TT('Secure connection to server'), #: Server SSL tickbox 'opt-ssl_verify' : TT('Certificate verification'), 'explain-ssl_verify' : TT('Minimal: when SSL is enabled, verify the identity of the server using its certificates. Strict: verify and enforce matching hostname.'), 'ssl_verify-disabled' : TT('Disabled'), 'ssl_verify-normal' : TT('Minimal'), 'ssl_verify-strict' : TT('Strict'), 'srv-priority' : TT('Priority'), #: Server priority 'explain-svrprio' : TT('0 is highest priority, 100 is the lowest priority'), #: Explain server priority 'srv-optional' : TT('Optional'), #: Server optional tickbox 'explain-optional' : TT('For unreliable servers, will be ignored longer in case of failures'), #: Explain server optional tickbox 'srv-enable' : TT('Enable'), #: Enable server tickbox 'button-addServer' : TT('Add Server'), #: Button: Add server 'button-delServer' : TT('Remove Server'), #: Button: Remove server 'button-testServer' : TT('Test Server'), #: Button: Test server 'button-clrServer' : TT('Clear Counters'), #: Button: Clear server's byte counters 'srv-testing' : TT('Testing server details...'), 'srv-bandwidth' : TT('Bandwidth'), 'srv-send_group' : TT('Send Group'), 'srv-explain-send_group' : TT('Send group command before requesting articles.'), 'srv-categories' : TT('Categories'), 'srv-explain-categories' : TT('Only use this server for these categories.'), 'srv-explain-no-categories' : TT('None of the enabled servers have the \'Default\' category selected. Jobs in the queue that are not assigned to one of the server\'s categories will not be downloaded.'), 'srv-notes' : TT('Personal notes'), # Config->Scheduling 'addSchedule' : TT('Add Schedule'), #:Config->Scheduling 'sch-frequency' : TT('Frequency'), #:Config->Scheduling 'sch-action' : TT('Action'), #:Config->Scheduling 'sch-arguments' : TT('Arguments'), #:Config->Scheduling 'button-addSchedule' : TT('Add Schedule'), #:Config->Scheduling 'currentSchedules' : TT('Current Schedules'), #:Config->Scheduling 'sch-resume' : TT('Resume'), #:Config->Scheduling 'sch-pause' : TT('Pause'), #:Config->Scheduling 'sch-shutdown' : TT('Shutdown'), #:Config->Scheduling 'sch-restart' : TT('Restart'), #:Config->Scheduling # Config->RSS 'explain-RSS' : TT('The checkbox next to the feed name should be ticked for the feed to be enabled and be automatically checked for new items.
When a feed is added, it will only pick up new items and not anything already in the RSS feed unless you press "Force Download".'), 'feed' : TT('Feed'), #: Config->RSS, tab header 'addMultipleFeeds' : TT('Seperate multiple URLs by a comma'), #: Config->RSS, placeholder (cannot be too long) 'button-preFeed' : TT('Read Feed'),#: Config->RSS button 'button-forceFeed' : TT('Force Download'),#: Config->RSS button 'rss-order' : TT('Order'), #: Config->RSS table column header 'rss-type' : TT('Type'), #: Config->RSS table column header 'rss-filter' : TT('Filter'), #: Config->RSS table column header 'rss-accept' : TT('Accept'), #: Config->RSS filter-type selection menu 'rss-reject' : TT('Reject'), #: Config->RSS filter-type selection menu 'rss-must' : TT('Requires'), #: Config->RSS filter-type selection menu 'rss-mustcat' : TT('RequiresCat'), #: Config->RSS filter-type selection menu 'rss-atleast' : TT('At least'), #: Config->RSS filter-type selection menu 'rss-atmost' : TT('At most'), #: Config->RSS filter-type selection menu 'rss-from' : TT('From SxxEyy'), #: Config->RSS filter-type selection menu "From Season/Episode" 'rss-from-show' : TT('From Show SxxEyy'), #: Config->RSS filter-type selection menu "From Show Season/Episode" 'rss-matched' : TT('Matched'), #: Config->RSS section header 'rss-notMatched' : TT('Not Matched'), #: Config->RSS section header 'rss-done' : TT('Downloaded'), #: Config->RSS section header 'rss-added' : TT('Added NZB'), #: Config->RSS after adding to queue 'link-download' : TT('Download'), #: Config->RSS button "download item" 'button-rssNow' : TT('Read All Feeds Now'), #: Config->RSS button # Config->Notifications 'opt-email_endjob' : TT('Email Notification On Job Completion'), 'email-never' : TT('Never'), #: When to send email 'email-always' : TT('Always'), #: When to send email 'email-errorOnly' : TT('Error-only'), #: When to send email 'opt-email_full' : TT('Disk Full Notifications'), 'explain-email_full' : TT('Send email when disk is full and SABnzbd is paused.'), 'opt-email_rss' : TT('Send RSS notifications'), 'explain-email_rss' : TT('Send email when an RSS feed adds jobs to the queue.'), 'opt-email_server' : TT('SMTP Server'), 'explain-email_server' : TT('Set your ISP\'s server for outgoing email.'), 'opt-email_to' : TT('Email Recipient'), 'explain-email_to' : TT('Email address to send the email to.'), 'opt-email_from' : TT('Email Sender'), 'explain-email_from' : TT('Who should we say sent the email?'), 'opt-email_account' : TT('OPTIONAL Account Username'), 'explain-email_account' : TT('For authenticated email, account name.'), 'opt-email_pwd' : TT('OPTIONAL Account Password'), 'explain-email_pwd' : TT('For authenticated email, password.'), 'growlSettings' : TT('Growl'), #: Header Growl section 'opt-growl_enable' : TT('Enable Growl'), #: Don't translate "Growl" 'explain-growl_enable' : TT('Send notifications to Growl'), #: Don't translate "Growl" 'opt-growl_server' : TT('Server address'), #: Address of Growl server 'explain-growl_server' : TT('Only use for remote Growl server (host:port)'), #: Don't translate "Growl" 'opt-growl_password' : TT('Server password'), #: Growl server password 'explain-growl_password' : TT('Optional password for Growl server'), #: Don't translate "Growl" 'opt-ntfosd_enable' : TT('Enable NotifyOSD'), #: Don't translate "NotifyOSD" 'explain-ntfosd_enable' : TT('Send notifications to NotifyOSD'), #: Don't translate "NotifyOSD" 'opt-ncenter_enable' : TT('Notification Center'), 'explain-ncenter_enable' : TT('Send notifications to Notification Center'), 'opt-acenter_enable' : TT('Enable Windows Notifications'), 'testNotify' : TT('Test Notification'), 'section-NC' : TT('Notification Center'), #: Header for OSX Notfication Center section 'section-AC' : TT('Windows Notifications'), 'section-OSD' : TT('NotifyOSD'), #: Header for Ubuntu's NotifyOSD notifications section 'section-Prowl' : TT('Prowl'), #: Header for Prowl notification section 'opt-prowl_enable' : TT('Enable Prowl notifications'), #: Prowl settings 'explain-prowl_enable' : TT('Requires a Prowl account'), #: Prowl settings 'opt-prowl_apikey' : TT('API key for Prowl'), #: Prowl settings 'explain-prowl_apikey' : TT('Personal API key for Prowl (required)'), #: Prowl settings 'section-Pushover' : TT('Pushover'), #: Header for Pushover notification section 'opt-pushover_enable' : TT('Enable Pushover notifications'), #: Pushover settings 'explain-pushover_enable' : TT('Requires a Pushover account'), #: Pushoversettings 'opt-pushover_token' : TT('Application Token'), #: Pushover settings 'explain-pushover_token' : TT('Application token (required)'), #: Pushover settings 'opt-pushover_userkey' : TT('User Key'), #: Pushover settings 'explain-pushover_userkey' : TT('User Key (required)'), #: Pushover settings 'opt-pushover_device' : TT('Device(s)'), #: Pushover settings 'explain-pushover_device' : TT('Device(s) to which message should be sent'), #: Pushover settings 'opt-pushover_emergency_retry' : TT('Emergency retry'), #: Pushover settings 'explain-pushover_emergency_retry' : TT('How often (in seconds) the same notification will be sent'), #: Pushover settings 'opt-pushover_emergency_expire' : TT('Emergency expire'), #: Pushover settings 'explain-pushover_emergency_expire' : TT('How many seconds your notification will continue to be retried'), #: Pushover settings 'section-Pushbullet' : TT('Pushbullet'), #: Header for Pushbullet notification section 'opt-pushbullet_enable' : TT('Enable Pushbullet notifications'), #: Pushbullet settings 'explain-pushbullet_enable' : TT('Requires a Pushbullet account'), #: Pushbulletsettings 'opt-pushbullet_apikey' : TT('Personal API key'), #: Pushbullet settings 'explain-pushbullet_apikey' : TT('Your personal Pushbullet API key (required)'), #: Pushbullet settings 'opt-pushbullet_device' : TT('Device'), #: Pushbullet settings 'explain-pushbullet_device' : TT('Device to which message should be sent'), #: Pushbullet settings 'section-NScript' : TT('Notification Script'), #: Header for Notification Script notification section 'opt-nscript_enable' : TT('Enable notification script'), #: Notification Script settings 'opt-nscript_script' : TT('Script'), #: Notification Script settings 'opt-nscript_parameters' : TT('Parameters'), #: Notification Script settings 'explain-nscript_enable' : TT('Executes a custom script'), #: Notification Scriptsettings 'explain-nscript_script' : TT('Which script should we execute for notification?'), #: Notification Scriptsettings 'explain-nscript_parameters' : TT('Read the Wiki Help on this!'), #: Notification Script settings # Config->Cat 'explain-catTags' : TT('Indexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to "Indexer Categories / Groups" to match more categories. Use commas to separate terms. Wildcards in the terms are supported.
More information can be found on the Wiki.'), 'explain-catTags2' : TT('Ending the path with an asterisk * will prevent creation of job folders.'), 'explain-relFolder' : TT('Relative folders are based on'), 'catFolderPath' : TT('Folder/Path'), 'catTags' : TT('Indexer Categories / Groups'), 'button-delCat' : TT('X'), #: Small delete button # Config->Sorting 'seriesSorting' : TT('Series Sorting'), 'opt-tvsort' : TT('Enable TV Sorting'), 'sort-legenda' : TT('Pattern Key'), 'button-clear' : TT('Clear'), 'button-evalFeed' : TT('Apply filters'), 'presetSort' : TT('Presets'), 'example' : TT('Example'), 'movieSort' : TT('Movie Sorting'), 'opt-movieSort' : TT('Enable Movie Sorting'), 'opt-movieExtra' : TT('Keep loose downloads in extra folders'), 'affectedCat' : TT('Affected Categories'), 'sort-meaning' : TT('Meaning'), 'sort-pattern' : TT('Pattern'), 'sort-result' : TT('Result'), 'button-Season1x05' : TT('1x05 Season Folder'), 'button-SeasonS01E05' : TT('S01E05 Season Folder'), 'button-Ep1x05' : TT('1x05 Episode Folder'), 'button-EpS01E05' : TT('S01E05 Episode Folder'), 'button-FileLikeFolder' : TT('Job Name as Filename'), 'sort-title' : TT('Title'), 'movie-sp-name' : TT('Movie Name'), 'movie-dot-name' : TT('Movie.Name'), 'movie-us-name' : TT('Movie_Name'), 'show-name' : TT('Show Name'), 'show-sp-name' : TT('Show Name'), 'show-dot-name' : TT('Show.Name'), 'show-us-name' : TT('Show_Name'), 'show-seasonNum' : TT('Season Number'), 'show-epNum' : TT('Episode Number'), 'ep-name' : TT('Episode Name'), 'ep-sp-name' : TT('Episode Name'), 'ep-dot-name' : TT('Episode.Name'), 'ep-us-name' : TT('Episode_Name'), 'fileExt' : TT('File Extension'), 'extension' : TT('Extension'), 'partNumber' : TT('Part Number'), 'decade' : TT('Decade'), 'orgFilename' : TT('Original Filename'), 'orgJobname' : TT('Original Job Name'), 'lowercase' : TT('Lower Case'), 'TEXT' : TT('TEXT'), 'text' : TT('text'), 'sort-File' : TT('file'), 'sortString' : TT('Sort String'), 'multiPartLabel' : TT('Multi-part label'), 'button-inFolders' : TT('In folders'), 'button-noFolders' : TT('No folders'), 'dateSorting' : TT('Date Sorting'), 'opt-dateSort' : TT('Enable Date Sorting'), 'button-ShowNameF' : TT('Show Name folder'), 'button-YMF' : TT('Year-Month Folders'), 'button-DailyF' : TT('Daily Folders'), 'case-adjusted' : TT('case-adjusted'), #: Note for title expression in Sorting that does case adjustment 'sortResult' : TT('Processed Result'), # Config->Special 'explain-special' : TT('Rarely used options. For their meaning and explanation, click on the Help button to go to the Wiki page.
' 'Don\'t change these without checking the Wiki first, as some have serious side-effects.
' 'The default values are between parentheses.'), 'sptag-boolean' : TT('Switches'), 'sptag-entries' : TT('Values'), # NZO 'nzoDetails' : TT('Edit NZB Details'), #: Job details page 'nzoName' : TT('Name'), #: Job details page 'nzo-delete' : TT('Delete'), #: Job details page, delete button 'nzo-top' : TT('Top'), #: Job details page, move file to top 'nzo-up' : TT('Up'), #: Job details page, move file one place up 'nzo-down' : TT('Down'), #: Job details page, move file one place down 'nzo-bottom' : TT('Bottom'), #: Job details page, move file to bottom 'nzo-all' : TT('All'), #: Job details page, select all files 'nzo-none' : TT('None'), #: Job details page, select no files 'nzo-invert' : TT('Invert'), #: Job details page, invert file selection 'nzo-filename' : TT('Filename'), #: Job details page, filename column header 'nzo-subject' : TT('Subject'), #: Job details page, subject column header 'nzo-age' : TT('Age'), #: Job details page, file age column header 'nzo-selection' : TT('Selection'), #: Job details page, section header 'nzo-action' : TT('Action'), #: Job details page, section header #Glitter skin 'Glitter-addNZB' : TT('Add NZB'), 'Glitter-pause5m' : TT('Pause for 5 minutes'), 'Glitter-pause15m' : TT('Pause for 15 minutes'), 'Glitter-pause30m' : TT('Pause for 30 minutes'), 'Glitter-pause1h' : TT('Pause for 1 hour'), 'Glitter-pause3h' : TT('Pause for 3 hours'), 'Glitter-pause6h' : TT('Pause for 6 hours'), 'Glitter-setMaxLinespeed' : TT('You must set a maximum bandwidth before you can set a bandwidth limit'), 'Glitter-left' : TT('left'), 'Glitter-free' : TT('Free Space'), 'Glitter-freeTemp' : TT('Temp Folder'), 'Glitter-search' : TT('Search'), 'Glitter-multiOperations' : TT('Multi-Operations'), 'Glitter-multiSelect' : TT('Hold shift key to select a range'), 'Glitter-checkAll' : TT('Check all'), 'Glitter-restartSab' : TT('Restart SABnzbd'), 'Glitter-onFinish' : TT('On queue finish'), 'Glitter-statusInterfaceOptions' : TT('Status and interface options'), 'Glitter-dragAndDrop' : TT('Or drag and drop files in the window!'), 'Glitter-today' : TT('Today'), 'Glitter-thisMonth' : TT('This month'), 'Glitter-total' : TT('Total'), 'Glitter-lostConnection' : TT('Lost connection to SABnzbd..'), 'Glitter-afterRestart' : TT('In case of SABnzbd restart this screen will disappear automatically!'), 'Glitter-disabled' : TT('Disabled'), 'Glitter-warning' : TT('WARNING:'), 'Glitter-encrypted' : TT('ENCRYPTED'), 'Glitter-incomplete' : TT('INCOMPLETE'), 'Glitter-duplicate' : TT('DUPLICATE'), 'Glitter-unwanted' : TT('UNWANTED'), 'Glitter-tooLarge' : TT('TOO LARGE'), 'Glitter-filtered' : TT('FILTERED'), 'Glitter-waitSec' : TT('WAIT %s sec'), 'Glitter-error' : TT('ERROR:'), 'Glitter-fetch' : TT('Fetch'), 'Glitter-interfaceOptions' : TT('Web Interface'), 'Glitter-interfaceRefresh' : TT('Refresh rate'), 'Glitter-useGlobalOptions' : TT('Use global interface settings'), 'Glitter-queueItemLimit' : TT('Queue item limit'), 'Glitter-historyItemLimit' : TT('History item limit'), 'Glitter-dateFormat' : TT('Date format'), 'Glitter-showExtraQueueColumn' : TT('Extra queue column'), 'Glitter-showExtraHistoryColumn' : TT('Extra history column'), 'Glitter-page' : TT('page'), 'Glitter-loading' : TT('Loading'), 'Glitter-articles' : TT('articles'), 'Glitter-rename' : TT('Rename'), 'Glitter-repairQueue' : TT('Queue repair'), 'Glitter-showActiveConnections' : TT('Show active connections'), 'Glitter-unblockServer' : TT('Unblock'), 'Glitter-orphanedJobs' : TT('Orphaned jobs'), 'Glitter-backToQueue' : TT('Send back to queue'), 'Glitter-purgeOrphaned' : TT('Delete All'), 'Glitter-retryAllOrphaned' : TT('Retry all'), 'Glitter-deleteJobAndFolders' : TT('Remove NZB & Delete Files'), 'Glitter-addFromURL' : TT('Fetch NZB from URL'), 'Glitter-addFromFile' : TT('Upload NZB'), 'Glitter-chooseFile' : TT('Browse'), 'Glitter-addnzbFilename' : TT('Optionally specify a filename'), 'Glitter-nzbFormats' : TT('Formats: .nzb, .rar, .zip, .gz, .bz2'), 'Glitter-submit' : TT('Submit'), 'Glitter-openInfoURL' : TT('Open Informational URL'), 'Glitter-sendThanks' : TT('Submitted. Thank you!'), 'Glitter-noSelect' : TT('Nothing selected!'), 'Glitter-removeSelected' : TT('Remove all selected files'), 'Glitter-toggleCompletedFiles' : TT('Hide/show completed files'), 'Glitter-top' : TT('Top'), 'Glitter-bottom' : TT('Bottom'), 'Glitter-retryJob' : TT('Retry'), 'Glitter-more' : TT('More'), 'Glitter-scriptLog' : TT('View Script Log'), 'Glitter-clearHistory' : TT('Purge History'), 'Glitter-confirmClearWarnings' : TT('Are you sure?'), 'Glitter-confirmClearDownloads' : TT('Are you sure?'), 'Glitter-confirmClear1Download' : TT('Are you sure?'), 'Glitter-updateAvailable' : TT('Update Available!'), 'Glitter-noLocalStorage' : TT('LocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!'), #: Don't translate LocalStorage 'Glitter-glitterTips' : TT('Glitter has some (new) features you might like!'), 'Glitter-custom' : TT('Custom'), 'Glitter-displayCompact' : TT('Compact layout'), 'Glitter-displayTabbed' : TT('Tabbed layout
(separate queue and history)'), 'Glitter-speed' : TT('Speed'), 'Glitter-confirmDeleteQueue' : TT('Confirm Queue Deletions'), 'Glitter-confirmDeleteHistory' : TT('Confirm History Deletions'), 'Glitter-pausePrompt': TT('How long or untill when do you want to pause? (in English!)'), 'Glitter-pausePromptFail': TT('Sorry, we could not interpret that. Try again.'), 'Glitter-pauseFor' : TT('Pause for...'), 'Glitter-refresh' : TT('Refresh'), 'Glitter-logText' : TT('All usernames, passwords and API-keys are automatically removed from the log and the included copy of your settings.'), 'Glitter-sortAgeAsc' : TT('Sort by Age Oldest→Newest'), 'Glitter-sortAgeDesc' : TT('Sort by Age Newest→Oldest'), 'Glitter-sortNameAsc' : TT('Sort by Name A→Z'), 'Glitter-sortNameDesc' : TT('Sort by Name Z→A'), 'Glitter-sortSizeAsc' : TT('Sort by Size Smallest→Largest'), 'Glitter-sortSizeDesc' : TT('Sort by Size Largest→Smallest'), 'Glitter-notification-uploading' : TT('Uploading'), # Notification window 'Glitter-notification-disconnect' : TT('Forcing disconnect'), # Notification window 'Glitter-notification-removing1' : TT('Removing job'), # Notification window 'Glitter-notification-removing' : TT('Removing jobs'), # Notification window 'Glitter-notification-shutdown' : TT('Shutting down'), # Notification window #Plush skin 'Plush-confirmWithoutSavingPrompt' : TT('Changes have not been saved, and will be lost.'), 'Plush-confirm' : TT('Are you sure?'), 'Plush-openInfoURL' : TT('Open Informational URL'), 'Plush-viewScriptLog' : TT('View Script Log'), 'Plush-prev' : TT('Prev'), 'Plush-next' : TT('Next'), 'Plush-confirmPurgeH' : TT('Purge the History?'), 'Plush-enableJavascript' : TT('You must enable JavaScript for Plush to function!'), 'Plush-addnzb' : TT('Add NZB'), 'Plush-button-refresh' : TT('Refresh'), 'Plush-options' : TT('Options'), 'Plush-updateAvailable' : TT('Update Available!'), 'Plush-pause5m' : TT('Pause for 5 minutes'), 'Plush-pause15m' : TT('Pause for 15 minutes'), 'Plush-pause30m' : TT('Pause for 30 minutes'), 'Plush-pause1h' : TT('Pause for 1 hour'), 'Plush-pause3h' : TT('Pause for 3 hours'), 'Plush-pause6h' : TT('Pause for 6 hours'), 'Plush-pauseForPrompt' : TT('Pause for how many minutes?'), 'Plush-pauseFor' : TT('Pause for...'), 'Plush-multiOperations' : TT('Multi-Operations'), 'Plush-topMenu' : TT('Top Menu'), 'Plush-onQueueFinish' : TT('On Finish'), 'Plush-sort' : TT('Sort'), 'Plush-sortAgeAsc' : TT('Sort by Age (Oldest→Newest)'), 'Plush-sortAgeDesc' : TT('Sort by Age (Newest→Oldest)'), 'Plush-sortNameAsc' : TT('Sort by Name (A→Z)'), 'Plush-sortNameDesc' : TT('Sort by Name (Z→A)'), 'Plush-sortSizeAsc' : TT('Sort by Size (Smallest→Largest)'), 'Plush-sortSizeDesc' : TT('Sort by Size (Largest→Smallest)'), 'Plush-confirmPurgeQ' : TT('Purge the Queue?'), 'Plush-confirmRetryQ' : TT('Retry all failed jobs in History?'), 'Plush-purge' : TT('Purge'), 'Plush-left' : TT('left'), 'Plush-maxSpeed' : TT('Max Speed'), #: Used in speed menu. Split in two lines if too long. 'Plush-nzo-range' : TT('Range'), 'Plush-reset' : TT('Reset'), 'Plush-applySelected' : TT('Apply to Selected'), 'Plush-page' : TT('page'), 'Plush-everything' : TT('Everything'), 'Plush-disabled' : TT('Disabled'), 'Plush-refreshRate' : TT('Refresh Rate'), 'Plush-containerWidth' : TT('Container Width'), 'Plush-confirmDeleteQueue' : TT('Confirm Queue Deletions'), 'Plush-confirmDeleteHistory' : TT('Confirm History Deletions'), 'Plush-explain-blockRefresh' : TT('This will prevent refreshing content when your mouse cursor is hovering over the queue.'), 'Plush-blockRefresh' : TT('Block Refreshes on Hover'), 'Plush-fetch' : TT('Fetch'), #: Fetch from URL button in "Add NZB" dialog box 'Plush-upload' : TT('Upload'), #: Upload button in "Add NZB" dialog box 'Plush-uploadTip' : TT('Upload: .nzb .rar .zip .gz, .bz2'), 'Plush-addnzb-filename' : TT('Optionally specify a filename'), 'Plush-progress' : TT('Progress'), 'Plush-remaining' : TT('Remaining'), 'Plush-notEnoughSpace' : TT('Not enough disk space to complete downloads!'), 'Plush-freeSpace' : TT('Free Space'), 'Plush-freeSpaceTemp' : TT('Free (Temp)'), 'Plush-idle' : TT('IDLE'), 'Plush-downloads' : TT('Downloads'), 'Plush-tab-repair' : TT('Queue repair'), #smpl skin 'smpl-purgehist' : TT('Delete Completed'), 'smpl-purgefailhistOK?' : TT('Delete the all failed items from the history?'), 'smpl-purgefailhist' : TT('Delete Failed'), 'smpl-retryAllJobs?' : TT('Retry all failed jobs?'), 'smpl-retryAll' : TT('Retry all'), #: Link in SMPL for "Retry all failed jobs" 'smpl-links' : TT('Links'), 'smpl-size' : TT('Size'), 'smpl-path' : TT('Path'), 'smpl-numresults@3' : TT('Showing %s to %s out of %s results'), 'smpl-noresult' : TT('No results'), 'smpl-oneresult' : TT('Showing one result'), 'smpl-first' : TT('First'), 'smpl-previous' : TT('Prev'), 'smpl-next' : TT('Next'), 'smpl-last' : TT('Last'), 'smpl-pauseForPrompt' : TT('Pause for how many minutes?'), 'smpl-paused' : TT('Paused'), 'smpl-downloading' : TT('Downloading'), 'smpl-idle' : TT('Idle'), 'smpl-emailsent' : TT('Email Sent!'), 'smpl-notesent' : TT('Notification Sent!'), 'smpl-saving' : TT('Saving..'), 'smpl-saved' : TT('Saved'), 'smpl-failed' : TT('Failed'), 'smpl-speed' : TT('Speed'), 'smpl-toggleadd' : TT('Toggle Add NZB'), 'smpl-dualView1' : TT('DualView1'), 'smpl-dualView2' : TT('DualView2'), 'smpl-warnings' : TT('Warnings'), 'smpl-custom' : TT('Custom'), 'smpl-restartOK?' : TT('Are you sure you want to restart SABnzbd?'), 'smpl-refreshr' : TT('Refresh rate'), 'smpl-purgeQueue' : TT('Delete All'), 'smpl-hideEdit' : TT('Hide Edit Options'), 'smpl-showEdit' : TT('Show Edit Options'), 'smpl-edit' : TT('Edit'), 'smpl-progress' : TT('Progress'), 'smpl-timeleft' : TT('Timeleft'), 'smpl-age' : TT('Age'), #Wizard 'wizard-quickstart' : TT('SABnzbd Quick-Start Wizard'), 'wizard-version' : TT('SABnzbd Version'), 'wizard-previous' : TT('Previous'), #: Button to go to previous Wizard page 'wizard-next' : TT('Next'), #: Button to go to next Wizard page 'wizard-server' : TT('Server Details'), 'wizard-explain-server' : TT('Please enter in the details of your primary usenet provider.'), 'wizard-server-con-explain' : TT('The number of connections allowed by your provider'), 'wizard-server-con-eg' : TT('E.g. 8 or 20'), #: Wizard: examples of amount of connections 'wizard-server-ssl-explain' : TT('Select only if your provider allows SSL connections.'), 'wizard-server-text' : TT('Click to test the entered details.'), 'wizard-example' : TT('E.g.'), #: Abbreviation for "for example" 'wizard-button-testServer' : TT('Test Server'), #: Wizard step 'wizard-complete' : TT('Setup is now complete!'), #: Wizard step 'wizard-tip1' : TT('SABnzbd will now be running in the background.'), #: Wizard tip 'wizard-tip2' : TT('Closing any browser windows/tabs will NOT close SABnzbd.'), #: Wizard tip 'wizard-tip4' : TT('It is recommended you right click and bookmark this location and use this bookmark to access SABnzbd when it is running in the background.'), #: Wizard tip 'wizard-tip-wiki' : TT('Further help can be found on our'), #: Will be appended with a wiki-link, adjust word order accordingly 'wizard-goto' : TT('Go to SABnzbd'), #: Wizard step 'wizard-exit' : TT('Exit SABnzbd'), #: Wizard EXIT button on first page 'wizard-start' : TT('Start Wizard'), #: Wizard START button on first page #Special 'yourRights' : TT(''' SABnzbd comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version. '''), 'wizard-ad-1': TT('In order to download from usenet you will require access to a provider. Your ISP may provide you with access, however a premium provider is recommended.'), 'wizard-ad-2': TT('Don\'t have a usenet provider? We recommend trying %s.'), } SABnzbd-2.3.2/sabnzbd/sorting.py0000644000000000000000000012717113217005257014624 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.sorting - Sorting Functions Series Sorting - Sorting downloads into seasons & episodes Date Sorting - Sorting downloads by a custom date matching Generic Sorting - Sorting large files by a custom matching """ import os import logging import re import sabnzbd from sabnzbd.misc import move_to_path, cleanup_empty_directories, get_unique_path, \ get_unique_filename, get_ext, renamer, sanitize_foldername, clip_path from sabnzbd.constants import series_match, date_match, year_match, sample_match from sabnzbd.encoding import unicoder import sabnzbd.cfg as cfg RE_SAMPLE = re.compile(sample_match, re.I) # Do not rename .vob files as they are usually DVD's EXCLUDED_FILE_EXTS = ('.vob', '.bin') LOWERCASE = ('the', 'of', 'and', 'at', 'vs', 'a', 'an', 'but', 'nor', 'for', 'on', 'so', 'yet', 'with') UPPERCASE = ('III', 'II', 'IV') REPLACE_AFTER = { '()': '', '..': '.', '__': '_', ' ': ' ', ' .%ext': '.%ext' } # Title() function messes up country names, so need to replace them instead COUNTRY_REP = ('(US)', '(UK)', '(EU)', '(CA)', '(YU)', '(VE)', '(TR)', '(CH)', '(SE)', '(ES)', '(KR)', '(ZA)', '(SK)', '(SG)', '(RU)', '(RO)', '(PR)', '(PT)', '(PL)', '(PH)', '(PK)', '(NO)', '(NG)', '(NZ)', '(NL)', '(MX)', '(MY)', '(MK)', '(KZ)', '(JP)', '(JM)', '(IT)', '(IL)', '(IE)', '(IN)', '(IS)', '(HU)', '(HK)', '(HN)', '(GR)', '(GH)', '(DE)', '(FR)', '(FI)', '(DK)', '(CZ)', '(HR)', '(CR)', '(CO)', '(CN)', '(CL)', '(BG)', '(BR)', '(BE)', '(AT)', '(AU)', '(AW)', '(AR)', '(AL)', '(AF)') def ends_in_file(path): """ Return True when path ends with '.%ext' or '%fn' """ _RE_ENDEXT = re.compile(r'\.%ext[{}]*$', re.I) _RE_ENDFN = re.compile(r'%fn[{}]*$', re.I) return bool(_RE_ENDEXT.search(path) or _RE_ENDFN.search(path)) def move_to_parent_folder(workdir): """ Move all in 'workdir' into 'workdir/..' """ # Determine 'folder'/.. workdir = os.path.abspath(os.path.normpath(workdir)) dest = os.path.abspath(os.path.normpath(os.path.join(workdir, '..'))) # Check for DVD folders and stop if found for item in os.listdir(workdir): if item.lower() in ('video_ts', 'audio_ts', 'bdmv'): return workdir, True for root, dirs, files in os.walk(workdir): for _file in files: path = os.path.join(root, _file) new_path = path.replace(workdir, dest) ok, new_path = move_to_path(path, new_path) if not ok: return dest, False cleanup_empty_directories(workdir) return dest, True class Sorter(object): """ Generic Sorter class """ def __init__(self, nzo, cat): self.sorter = None self.type = None self.sort_file = False self.nzo = nzo self.cat = cat self.ext = '' def detect(self, job_name, complete_dir): """ Detect which kind of sort applies """ self.sorter = SeriesSorter(self.nzo, job_name, complete_dir, self.cat) if self.sorter.matched: complete_dir = self.sorter.get_final_path() self.type = 'tv' self.sort_file = True return complete_dir self.sorter = DateSorter(self.nzo, job_name, complete_dir, self.cat) if self.sorter.matched: complete_dir = self.sorter.get_final_path() self.type = 'date' self.sort_file = True return complete_dir self.sorter = MovieSorter(self.nzo, job_name, complete_dir, self.cat) if self.sorter.matched: complete_dir = self.sorter.get_final_path() self.type = 'movie' self.sort_file = True return complete_dir self.sort_file = False return complete_dir def rename(self, newfiles, workdir_complete): """ Rename files of the job """ if self.sorter.rename_or_not: self.sorter.rename(newfiles, workdir_complete) def rename_with_ext(self, workdir_complete): """ Special renamer for %ext """ if self.sorter.rename_or_not and '%ext' in workdir_complete and self.ext: # Replace %ext with extension newpath = workdir_complete.replace('%ext', self.ext) try: renamer(workdir_complete, newpath) except: return newpath, False return newpath, True else: return workdir_complete, True def move(self, workdir_complete): ok = True if self.type == 'movie': move_to_parent = True # check if we should leave the files inside an extra folder if cfg.movie_extra_folders(): # if there is a folder in the download, leave it in an extra folder move_to_parent = not check_for_folder(workdir_complete) if move_to_parent: workdir_complete, ok = move_to_parent_folder(workdir_complete) else: workdir_complete, ok = move_to_parent_folder(workdir_complete) if not ok: return workdir_complete, False path, part = os.path.split(workdir_complete) if '%fn' in part and self.sorter.fname: old = workdir_complete workdir_complete = os.path.join(path, part.replace('%fn', self.sorter.fname)) workdir_complete = get_unique_path(workdir_complete, create_dir=False) try: renamer(old, workdir_complete) except: logging.error(T('Cannot create directory %s'), clip_path(workdir_complete)) workdir_complete = old ok = False return workdir_complete, ok class SeriesSorter(object): """ Methods for Series Sorting """ def __init__(self, nzo, job_name, path, cat): self.matched = False self.original_job_name = job_name self.original_path = path self.nzo = nzo self.cat = cat self.sort_string = cfg.tv_sort_string() self.cats = cfg.tv_categories() self.filename_set = '' self.fname = '' # Value for %fn substitution in folders self.final_path = '' self.match_obj = None self.extras = None self.rename_or_not = False self.show_info = {} # Check if it is a TV show on init() self.match() def match(self, force=False): """ Checks the regex for a match, if so set self.match to true """ if force or (cfg.enable_tv_sorting() and cfg.tv_sort_string()): if force or (not self.cats) or (self.cat and self.cat.lower() in self.cats) or (not self.cat and 'None' in self.cats): # First check if the show matches TV episode regular expressions. Returns regex match object self.match_obj, self.extras = check_regexs(self.original_job_name, series_match) if self.match_obj: logging.debug("Found TV Show (%s)", self.original_job_name) self.matched = True def is_match(self): """ Returns whether there was a match or not """ return self.matched def get_final_path(self): """ Collect and construct all the variables such as episode name, show names """ if self.get_values(): # Get the final path path = self.construct_path() self.final_path = os.path.join(self.original_path, path) return self.final_path else: # Error Sorting return os.path.join(self.original_path, self.original_job_name) def get_multi_ep_naming(self, one, two, extras): """ Returns a list of unique values joined into a string and separated by - (ex:01-02-03-04) """ extra_list = [one] extra2_list = [two] for extra in extras: if extra not in (extra_list, extra2_list): ep_no2 = extra.rjust(2, '0') extra_list.append(extra) extra2_list.append(ep_no2) one = '-'.join(extra_list) two = '-'.join(extra2_list) return (one, two) def get_shownames(self): """ Get the show name from the match object and format it """ # Get the formatted title and alternate title formats self.show_info['show_tname'], self.show_info['show_tname_two'], self.show_info['show_tname_three'] = get_titles(self.nzo, self.match_obj, self.original_job_name, True) self.show_info['show_name'], self.show_info['show_name_two'], self.show_info['show_name_three'] = get_titles(self.nzo, self.match_obj, self.original_job_name) def get_seasons(self): """ Get the season number from the match object and format it """ try: season = self.match_obj.group(1).strip('_') # season number except AttributeError: season = '1' # Provide alternative formatting (0 padding) if season.lower() == 's': season2 = season else: try: season = str(int(season)) except: pass season2 = season.rjust(2, '0') self.show_info['season_num'] = season self.show_info['season_num_alt'] = season2 def get_episodes(self): """ Get the episode numbers from the match object, format and join them """ try: ep_no = self.match_obj.group(2) # episode number except AttributeError: ep_no = '1' # Store the original episode number # Provide alternative formatting (0 padding) ep_no2 = ep_no.rjust(2, '0') try: ep_no = str(int(ep_no)) except: pass # Dual episode support if self.extras: ep_no, ep_no2 = self.get_multi_ep_naming(ep_no, ep_no2, self.extras) self.show_info['episode_num'] = ep_no self.show_info['episode_num_alt'] = ep_no2 def get_showdescriptions(self): """ Get the show descriptions from the match object and format them """ self.show_info['ep_name'], self.show_info['ep_name_two'], self.show_info['ep_name_three'] = get_descriptions(self.nzo, self.match_obj, self.original_job_name) def get_values(self): """ Collect and construct all the values needed for path replacement """ try: # - Show Name self.get_shownames() # - Season self.get_seasons() # - Episode Number self.get_episodes() # - Episode Name self.get_showdescriptions() return True except: logging.error(T('Error getting TV info (%s)'), clip_path(self.original_job_name)) logging.info("Traceback: ", exc_info=True) return False def construct_path(self): """ Replaces the sort string with real values such as Show Name and Episode Number """ sorter = self.sort_string.replace('\\', '/') mapping = [] if ends_in_file(sorter): extension = True sorter = sorter.replace('.%ext', '') else: extension = False # Replace Show name mapping.append(('%sn', self.show_info['show_tname'])) mapping.append(('%s.n', self.show_info['show_tname_two'])) mapping.append(('%s_n', self.show_info['show_tname_three'])) mapping.append(('%sN', self.show_info['show_name'])) mapping.append(('%s.N', self.show_info['show_name_two'])) mapping.append(('%s_N', self.show_info['show_name_three'])) # Replace season number mapping.append(('%s', self.show_info['season_num'])) mapping.append(('%0s', self.show_info['season_num_alt'])) # Original dir name mapping.append(('%dn', self.original_job_name)) # Replace episode names if self.show_info['ep_name']: mapping.append(('%en', self.show_info['ep_name'])) mapping.append(('%e.n', self.show_info['ep_name_two'])) mapping.append(('%e_n', self.show_info['ep_name_three'])) else: mapping.append(('%en', '')) mapping.append(('%e.n', '')) mapping.append(('%e_n', '')) # Replace episode number mapping.append(('%e', self.show_info['episode_num'])) mapping.append(('%0e', self.show_info['episode_num_alt'])) # Make sure unsupported %desc is removed mapping.append(('%desc', '')) # Replace elements path = path_subst(sorter, mapping) for key, name in REPLACE_AFTER.iteritems(): path = path.replace(key, name) # Lowercase all characters wrapped in {} path = to_lowercase(path) # Strip any extra ' ' '.' or '_' around foldernames path = strip_folders(path) # Split the last part of the path up for the renamer if extension: head, tail = os.path.split(path) self.filename_set = tail self.rename_or_not = True else: head = path return os.path.normpath(head) def rename(self, files, current_path): """ Rename for Series """ logging.debug("Renaming Series") largest = (None, None, 0) def to_filepath(f, current_path): if is_full_path(f): filepath = os.path.normpath(f) else: filepath = os.path.normpath(os.path.join(current_path, f)) return filepath # Create a generator of filepaths, ignore sample files and excluded files (vobs ect) filepaths = ((file, to_filepath(file, current_path)) for file in files if not RE_SAMPLE.search(file) and get_ext(file) not in EXCLUDED_FILE_EXTS) # Find the largest existing file for file, fp in filepaths: # If for some reason the file no longer exists, skip if not os.path.exists(fp): continue size = os.stat(fp).st_size f_file, f_fp, f_size = largest if size > f_size: largest = (file, fp, size) file, filepath, size = largest # >20MB if filepath and size > 20971520: self.fname, self.ext = os.path.splitext(os.path.split(file)[1]) newname = "%s%s" % (self.filename_set, self.ext) # Replace %fn with the original filename newname = newname.replace('%fn', self.fname) newpath = os.path.join(current_path, newname) # Replace %ext with extension newpath = newpath.replace('%ext', self.ext) try: logging.debug("Rename: %s to %s", filepath, newpath) renamer(filepath, newpath) except: logging.error(T('Failed to rename: %s to %s'), clip_path(current_path), clip_path(newpath)) logging.info("Traceback: ", exc_info=True) rename_similar(current_path, self.ext, self.filename_set, ()) else: logging.debug('Nothing to rename, %s', files) _RE_MULTIPLE = ( re.compile(r'cd\W?(\d+)\W?', re.I), # .cd1.mkv re.compile(r'\w\W?([\w\d])[{}]*$', re.I), # blah1.mkv blaha.mkv re.compile(r'\w\W([\w\d])\W', re.I) # blah-1-ok.mkv blah-a-ok.mkv ) def check_for_multiple(files): """ Return list of files that looks like a multi-part post """ for regex in _RE_MULTIPLE: matched_files = check_for_sequence(regex, files) if matched_files: return matched_files return '' def check_for_sequence(regex, files): """ Return list of files that looks like a sequence, using 'regex' """ matches = {} prefix = None # Build up a dictionary of matches # The key is based off the match, ie {1:'blah-part1.mkv'} for _file in files: name, ext = os.path.splitext(_file) match1 = regex.search(name) if match1: if not prefix or prefix == name[:match1.start()]: matches[match1.group(1)] = name + ext prefix = name[:match1.start()] # Don't do anything if only one or no files matched if len(matches.keys()) < 2: return {} key_prev = 0 passed = True alphabet = 'abcdefghijklmnopqrstuvwxyz' # Check the dictionary to see if the keys are in a numeric or alphabetic sequence for akey in sorted(matches.keys()): if akey.isdigit(): key = int(akey) elif akey in alphabet: key = alphabet.find(akey) + 1 else: passed = False if passed: if not key_prev: key_prev = key else: if key_prev + 1 == key: key_prev = key else: passed = False if passed: # convert {'b':'filename-b.mkv'} to {'2', 'filename-b.mkv'} item = matches.pop(akey) matches[str(key)] = item if passed: return matches else: return {} class MovieSorter(object): """ Methods for Generic Sorting """ def __init__(self, nzo, job_name, path, cat): self.matched = False self.original_job_name = job_name self.original_path = path self.sort_string = cfg.movie_sort_string() self.extra = cfg.movie_sort_extra() self.cats = cfg.movie_categories() self.cat = cat self.nzo = nzo self.filename_set = '' self.fname = '' # Value for %fn substitution in folders self.final_path = '' self.match_obj = None self.rename_or_not = False self.movie_info = {} # Check if we match the category in init() self.match() def match(self, force=False): """ Checks the category for a match, if so set self.match to true """ if force or (cfg.enable_movie_sorting() and self.sort_string): # First check if the show matches TV episode regular expressions. Returns regex match object if force or (self.cat and self.cat.lower() in self.cats) or (not self.cat and 'None' in self.cats): logging.debug("Found Movie (%s)", self.original_job_name) self.matched = True def get_final_path(self): """ Collect and construct all the variables such as episode name, show names """ if self.get_values(): # Get the final path path = self.construct_path() self.final_path = os.path.join(self.original_path, path) return self.final_path else: # Error Sorting return os.path.join(self.original_path, self.original_job_name) def get_values(self): """ Collect and construct all the values needed for path replacement """ # - Get Year if self.nzo: year = self.nzo.nzo_info.get('year') else: year = '' if year: year_m = None else: job_name = self.original_job_name.replace('_', ' ') RE_YEAR = re.compile(year_match, re.I) year_m = RE_YEAR.search(job_name) if year_m: # Find the last matched date # Keep year_m to use in get_titles year = RE_YEAR.findall(job_name)[-1][0] else: year = '' self.movie_info['year'] = year # - Get Decades self.movie_info['decade'], self.movie_info['decade_two'] = get_decades(year) # - Get Title self.movie_info['ttitle'], self.movie_info['ttitle_two'], self.movie_info['ttitle_three'] = get_titles(self.nzo, year_m, self.original_job_name, True) self.movie_info['title'], self.movie_info['title_two'], self.movie_info['title_three'] = get_titles(self.nzo, year_m, self.original_job_name) return True def construct_path(self): """ Return path reconstructed from original and sort expression """ sorter = self.sort_string.replace('\\', '/') mapping = [] if ends_in_file(sorter): extension = True sorter = sorter.replace(".%ext", '') else: extension = False # Replace title mapping.append(('%title', self.movie_info['title'])) mapping.append(('%.title', self.movie_info['title_two'])) mapping.append(('%_title', self.movie_info['title_three'])) # Replace title (short forms) mapping.append(('%t', self.movie_info['title'])) mapping.append(('%.t', self.movie_info['title_two'])) mapping.append(('%_t', self.movie_info['title_three'])) mapping.append(('%sn', self.movie_info['title'])) mapping.append(('%s.n', self.movie_info['title_two'])) mapping.append(('%s_n', self.movie_info['title_three'])) mapping.append(('%sN', self.movie_info['ttitle'])) mapping.append(('%s.N', self.movie_info['ttitle_two'])) mapping.append(('%s_N', self.movie_info['ttitle_three'])) # Replace year mapping.append(('%y', self.movie_info['year'])) # Replace decades mapping.append(('%decade', self.movie_info['decade'])) mapping.append(('%0decade', self.movie_info['decade_two'])) # Original dir name mapping.append(('%dn', self.original_job_name)) path = path_subst(sorter, mapping) for key, name in REPLACE_AFTER.iteritems(): path = path.replace(key, name) # Lowercase all characters wrapped in {} path = to_lowercase(path) # Strip any extra ' ' '.' or '_' around foldernames path = strip_folders(path) # Split the last part of the path up for the renamer if extension: head, tail = os.path.split(path) self.filename_set = tail self.rename_or_not = True else: head = path return os.path.normpath(head) def rename(self, _files, current_path): """ Rename for Generic files """ logging.debug("Renaming Generic file") def filter_files(_file, current_path): if is_full_path(_file): filepath = os.path.normpath(_file) else: filepath = os.path.normpath(os.path.join(current_path, _file)) if os.path.exists(filepath): size = os.stat(filepath).st_size if size >= cfg.movie_rename_limit.get_int() and not RE_SAMPLE.search(_file) \ and get_ext(_file) not in EXCLUDED_FILE_EXTS: return True return False # remove any files below the limit from this list files = [_file for _file in _files if filter_files(_file, current_path)] length = len(files) # Single File Handling if length == 1: file = files[0] if is_full_path(file): filepath = os.path.normpath(file) else: filepath = os.path.normpath(os.path.join(current_path, file)) if os.path.exists(filepath): self.fname, ext = os.path.splitext(os.path.split(file)[1]) newname = "%s%s" % (self.filename_set, ext) newname = newname.replace('%fn', self.fname) newpath = os.path.join(current_path, newname) try: logging.debug("Rename: %s to %s", filepath, newpath) renamer(filepath, newpath) except: logging.error(T('Failed to rename: %s to %s'), clip_path(filepath), clip_path(newpath)) logging.info("Traceback: ", exc_info=True) rename_similar(current_path, ext, self.filename_set, ()) # Sequence File Handling # if there is more than one extracted file check for CD1/1/A in the title elif self.extra: matched_files = check_for_multiple(files) # rename files marked as in a set if matched_files: logging.debug("Renaming a series of generic files (%s)", matched_files) renamed = matched_files.values() for index, file in matched_files.iteritems(): filepath = os.path.join(current_path, file) renamed.append(filepath) self.fname, ext = os.path.splitext(os.path.split(file)[1]) name = '%s%s' % (self.filename_set, self.extra) name = name.replace('%1', str(index)).replace('%fn', self.fname) name = name + ext newpath = os.path.join(current_path, name) try: logging.debug("Rename: %s to %s", filepath, newpath) renamer(filepath, newpath) except: logging.error(T('Failed to rename: %s to %s'), clip_path(filepath), clip_path(newpath)) logging.info("Traceback: ", exc_info=True) rename_similar(current_path, ext, self.filename_set, renamed) else: logging.debug("Movie files not in sequence %s", _files) class DateSorter(object): """ Methods for Date Sorting """ def __init__(self, nzo, job_name, path, cat): self.matched = False self.original_job_name = job_name self.original_path = path self.sort_string = cfg.date_sort_string() self.cats = cfg.date_categories() self.cat = cat self.nzo = nzo self.filename_set = '' self.fname = '' # Value for %fn substitution in folders self.match_obj = None self.rename_or_not = False self.date_type = None self.date_info = {} self.final_path = '' # Check if we match the category in init() self.match() def match(self, force=False): """ Checks the category for a match, if so set self.matched to true """ if force or (cfg.enable_date_sorting() and self.sort_string): # First check if the show matches TV episode regular expressions. Returns regex match object if force or (self.cat and self.cat.lower() in self.cats) or (not self.cat and 'None' in self.cats): self.match_obj, self.date_type = check_for_date(self.original_job_name, date_match) if self.match_obj: logging.debug("Found date for sorting (%s)", self.original_job_name) self.matched = True def is_match(self): """ Returns whether there was a match or not """ return self.matched def get_final_path(self): """ Collect and construct all the variables such as episode name, show names """ if self.get_values(): # Get the final path path = self.construct_path() self.final_path = os.path.join(self.original_path, path) return self.final_path else: # Error Sorting return os.path.join(self.original_path, self.original_job_name) def get_values(self): """ Collect and construct all the values needed for path replacement """ # 2008-10-16 if self.date_type == 1: self.date_info['year'] = self.match_obj.group(1) self.date_info['month'] = self.match_obj.group(2) self.date_info['date'] = self.match_obj.group(3) # 10.16.2008 else: self.date_info['year'] = self.match_obj.group(3) self.date_info['month'] = self.match_obj.group(1) self.date_info['date'] = self.match_obj.group(2) self.date_info['month_two'] = self.date_info['month'].rjust(2, '0') self.date_info['date_two'] = self.date_info['date'].rjust(2, '0') # - Get Decades self.date_info['decade'], self.date_info['decade_two'] = get_decades(self.date_info['year']) # - Get Title self.date_info['ttitle'], self.date_info['ttitle_two'], self.date_info['ttitle_three'] = get_titles(self.nzo, self.match_obj, self.original_job_name, True) self.date_info['title'], self.date_info['title_two'], self.date_info['title_three'] = get_titles(self.nzo, self.match_obj, self.original_job_name) self.date_info['ep_name'], self.date_info['ep_name_two'], self.date_info['ep_name_three'] = get_descriptions(self.nzo, self.match_obj, self.original_job_name) return True def construct_path(self): """ Return path reconstructed from original and sort expression """ sorter = self.sort_string.replace('\\', '/') mapping = [] if ends_in_file(sorter): extension = True sorter = sorter.replace(".%ext", '') else: extension = False # Replace title mapping.append(('%title', self.date_info['title'])) mapping.append(('%.title', self.date_info['title_two'])) mapping.append(('%_title', self.date_info['title_three'])) mapping.append(('%t', self.date_info['title'])) mapping.append(('%.t', self.date_info['title_two'])) mapping.append(('%_t', self.date_info['title_three'])) mapping.append(('%sn', self.date_info['ttitle'])) mapping.append(('%s.n', self.date_info['ttitle_two'])) mapping.append(('%s_n', self.date_info['ttitle_three'])) mapping.append(('%sN', self.date_info['title'])) mapping.append(('%s.N', self.date_info['title_two'])) mapping.append(('%s_N', self.date_info['title_three'])) # Replace year mapping.append(('%year', self.date_info['year'])) mapping.append(('%y', self.date_info['year'])) if self.date_info['ep_name']: mapping.append(('%desc', self.date_info['ep_name'])) mapping.append(('%.desc', self.date_info['ep_name_two'])) mapping.append(('%_desc', self.date_info['ep_name_three'])) else: mapping.append(('%desc', '')) mapping.append(('%.desc', '')) mapping.append(('%_desc', '')) # Replace dir-name before replacing %d for month mapping.append(('%dn', self.original_job_name)) # Replace decades mapping.append(('%decade', self.date_info['decade'])) mapping.append(('%0decade', self.date_info['decade_two'])) # Replace month mapping.append(('%m', self.date_info['month'])) mapping.append(('%0m', self.date_info['month_two'])) # Replace date mapping.append(('%d', self.date_info['date'])) mapping.append(('%0d', self.date_info['date_two'])) path = path_subst(sorter, mapping) for key, name in REPLACE_AFTER.iteritems(): path = path.replace(key, name) # Lowercase all characters wrapped in {} path = to_lowercase(path) # Strip any extra ' ' '.' or '_' around foldernames path = strip_folders(path) # Split the last part of the path up for the renamer if extension: head, tail = os.path.split(path) self.filename_set = tail self.rename_or_not = True else: head = path return os.path.normpath(head) def rename(self, files, current_path): """ Renaming Date file """ logging.debug("Renaming Date file") # find the master file to rename for file in files: if is_full_path(file): filepath = os.path.normpath(file) else: filepath = os.path.normpath(os.path.join(current_path, file)) if os.path.exists(filepath): size = os.stat(filepath).st_size if size > cfg.movie_rename_limit.get_int(): if 'sample' not in file: self.fname, ext = os.path.splitext(os.path.split(file)[1]) newname = "%s%s" % (self.filename_set, ext) newname = newname.replace('%fn', self.fname) newpath = os.path.join(current_path, newname) if not os.path.exists(newpath): try: logging.debug("Rename: %s to %s", filepath, newpath) renamer(filepath, newpath) except: logging.error(T('Failed to rename: %s to %s'), clip_path(current_path), clip_path(newpath)) logging.info("Traceback: ", exc_info=True) rename_similar(current_path, ext, self.filename_set, ()) break def path_subst(path, mapping): """ Replace the sort sting elements by real values. Non-elements are copied literally. path = the sort string mapping = array of tuples that maps all elements to their values """ # Added ugly hack to prevent %ext from being masked by %e newpath = [] plen = len(path) n = 0 while n < plen: result = path[n] if result == '%': for key, value in mapping: if path.startswith(key, n) and not path.startswith('%ext', n): n += len(key) - 1 result = value break newpath.append(result) n += 1 return u''.join([unicoder(x) for x in newpath]) def get_titles(nzo, match, name, titleing=False): """ The title will be the part before the match Clean it up and title() it ''.title() isn't very good under python so this contains a lot of little hacks to make it better and for more control """ if nzo: title = nzo.nzo_info.get('propername') else: title = '' if not title: if match: name = name[:match.start()] # Replace .US. with (US) if cfg.tv_sort_countries() == 1: for rep in COUNTRY_REP: # (us) > (US) name = replace_word(name, rep.lower(), rep) # (Us) > (US) name = replace_word(name, rep.title(), rep) # .US. > (US) dotted_country = '.%s.' % (rep.strip('()')) name = replace_word(name, dotted_country, rep) # Remove .US. and (US) elif cfg.tv_sort_countries() == 2: for rep in COUNTRY_REP: # Remove (US) name = replace_word(name, rep, '') dotted_country = '.%s.' % (rep.strip('()')) # Remove .US. name = replace_word(name, dotted_country, '.') title = name.replace('.', ' ').replace('_', ' ') title = title.strip().strip('(').strip('_').strip('-').strip().strip('_') if titleing: title = title.title() # title the show name so it is in a consistent letter case # title applied uppercase to 's Python bug? title = title.replace("'S", "'s") # Replace titled country names, (Us) with (US) and so on if cfg.tv_sort_countries() == 1: for rep in COUNTRY_REP: title = title.replace(rep.title(), rep) # Remove country names, ie (Us) elif cfg.tv_sort_countries() == 2: for rep in COUNTRY_REP: title = title.replace(rep.title(), '').strip() # Make sure some words such as 'and' or 'of' stay lowercased. for x in LOWERCASE: xtitled = x.title() title = replace_word(title, xtitled, x) # Make sure some words such as 'III' or 'IV' stay uppercased. for x in UPPERCASE: xtitled = x.title() title = replace_word(title, xtitled, x) # Make sure the first letter of the title is always uppercase if title: title = title[0].title() + title[1:] # The title with spaces replaced by dots dots = title.replace(" - ", "-").replace(' ', '.').replace('_', '.') dots = dots.replace('(', '.').replace(')', '.').replace('..', '.').rstrip('.') # The title with spaces replaced by underscores underscores = title.replace(' ', '_').replace('.', '_').replace('__', '_').rstrip('_') return title, dots, underscores def replace_word(word_input, one, two): """ Regex replace on just words """ regex = re.compile(r'\W(%s)(\W|$)' % one, re.I) matches = regex.findall(word_input) if matches: for unused in matches: word_input = word_input.replace(one, two) return word_input def get_descriptions(nzo, match, name): """ If present, get a description from the nzb name. A description has to be after the matched item, separated either like ' - Description' or '_-_Description' """ if nzo: ep_name = nzo.nzo_info.get('episodename') else: ep_name = '' if not ep_name: if match: ep_name = name[match.end():] # Need to improve for multi-ep support else: ep_name = name ep_name = ep_name.strip(' _.') if ep_name.startswith('-'): ep_name = ep_name.strip('- _.') if '.' in ep_name and ' ' not in ep_name: ep_name = ep_name.replace('.', ' ') ep_name = ep_name.replace('_', ' ') ep_name2 = ep_name.replace(" - ", "-").replace(" ", ".") ep_name3 = ep_name.replace(" ", "_") return ep_name, ep_name2, ep_name3 def get_decades(year): """ Return 4 digit and 2 digit decades given 'year' """ if year: try: decade = year[2:3] + '0' decade2 = year[:3] + '0' except: decade = '' decade2 = '' else: decade = '' decade2 = '' return decade, decade2 def check_for_folder(path): """ Return True if any folder is found in the tree at 'path' """ for _root, dirs, _files in os.walk(path): if dirs: return True return False def to_lowercase(path): """ Lowercases any characters enclosed in {} """ _RE_LOWERCASE = re.compile(r'{([^{]*)}') while True: m = _RE_LOWERCASE.search(path) if not m: break path = path[:m.start()] + m.group(1).lower() + path[m.end():] # just in case path = path.replace('{', '') path = path.replace('}', '') return path def strip_folders(path): """ Return 'path' without leading and trailing spaces and underscores in each element For Windows, also remove leading and trailing dots """ unc = sabnzbd.WIN32 and (path.startswith('//') or path.startswith('\\\\')) f = path.strip('/').split('/') # For path beginning with a slash, insert empty element to prevent loss if path.strip()[0] in '/\\': f.insert(0, '') def strip_all(x): """ Strip all leading/trailing underscores also dots for Windows """ x = x.strip().strip('_') if sabnzbd.WIN32: # OSX and Linux should keep dots, because leading dots are significant # while Windows cannot handle trailing dots x = x.strip('.') x = x.strip() return x path = os.path.normpath('/'.join([strip_all(x) for x in f])) if unc: return '\\' + path else: return path def rename_similar(folder, skip_ext, name, skipped_files): """ Rename all other files in the 'folder' hierarchy after 'name' and move them to the root of 'folder'. Files having extension 'skip_ext' will be moved, but not renamed. Don't touch files in list `skipped_files` """ logging.debug('Give files in set "%s" matching names.', name) folder = os.path.normpath(folder) skip_ext = skip_ext.lower() for root, dirs, files in os.walk(folder): for f in files: path = os.path.join(root, f) if path in skipped_files: continue org, ext = os.path.splitext(f) if ext.lower() == skip_ext: # Move file, but do not rename newpath = os.path.join(folder, f) else: # Move file and rename newname = "%s%s" % (name, ext) newname = newname.replace('%fn', org) newpath = os.path.join(folder, newname) if path != newpath: newpath = get_unique_filename(newpath) try: logging.debug("Rename: %s to %s", path, newpath) renamer(path, newpath) except: logging.error(T('Failed to rename similar file: %s to %s'), clip_path(path), clip_path(newpath)) logging.info("Traceback: ", exc_info=True) cleanup_empty_directories(folder) def check_regexs(filename, matchers): """ Regular Expression match for a list of regexes Returns the MatchObject if a match is made This version checks for an additional match """ extras = [] for expressions in matchers: expression, extramatchers = expressions match1 = expression.search(filename) if match1: for m in extramatchers: match2 = m.findall(filename, match1.end()) if match2: for match in match2: if type(match) == type(()) and len(match) > 1: extras.append(match[1]) else: extras.append(match) break return match1, extras return None, None def check_for_date(filename, matcher): """ Regular Expression match for date based files Returns the MatchObject if a match is made """ x = 0 if matcher: for expression in matcher: regex = re.compile(expression) match1 = regex.search(filename) x += 1 if match1: return match1, x return None, 0 def is_full_path(file): """ Return True if path is absolute """ if file.startswith('\\') or file.startswith('/'): return True try: if file[1:3] == ':\\': return True except: pass return False def eval_sort(sorttype, expression, name=None, multipart=''): """ Preview a sort expression, to be used by API """ from sabnzbd.api import Ttemplate path = '' name = sanitize_foldername(name) if sorttype == 'series': name = name or ('%s S01E05 - %s [DTS]' % (Ttemplate('show-name'), Ttemplate('ep-name'))) sorter = SeriesSorter(None, name, path, 'tv') elif sorttype == 'movie': name = name or (Ttemplate('movie-sp-name') + ' (2009)') sorter = MovieSorter(None, name, path, 'tv') elif sorttype == 'date': name = name or (Ttemplate('show-name') + ' 2009-01-02') sorter = DateSorter(None, name, path, 'tv') else: return None sorter.sort_string = expression sorter.match(force=True) path = sorter.get_final_path() path = os.path.normpath(os.path.join(path, sorter.filename_set)) fname = Ttemplate('orgFilename') fpath = path if sorttype == 'movie' and '%1' in multipart: fname = fname + multipart.replace('%1', '1') fpath = fpath + multipart.replace('%1', '1') if '%fn' in path: path = path.replace('%fn', fname + '.mkv') else: if sorter.rename_or_not: path = fpath + '.mkv' else: if sabnzbd.WIN32: path += '\\' else: path += '/' return path SABnzbd-2.3.2/sabnzbd/urlgrabber.py0000644000000000000000000003524013217005257015261 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.urlgrabber - Queue for grabbing NZB files from websites """ import os import sys import time import re import logging import Queue import urllib2 from httplib import IncompleteRead from threading import Thread import sabnzbd from sabnzbd.constants import DEF_TIMEOUT, MAX_URL_RETRIES, FUTURE_Q_FOLDER, Status from sabnzbd.encoding import unicoder import sabnzbd.misc as misc import sabnzbd.dirscanner as dirscanner from sabnzbd.nzbqueue import NzbQueue import sabnzbd.cfg as cfg import sabnzbd.emailer as emailer import sabnzbd.notifier as notifier _BAD_GZ_HOSTS = ('.zip', 'nzbsa.co.za', 'newshost.za.net') _RARTING_FIELDS = ('x-rating-id', 'x-rating-url', 'x-rating-host', 'x-rating-video', 'x-rating-videocnt', 'x-rating-audio', 'x-rating-audiocnt', 'x-rating-voteup', 'x-rating-votedown', 'x-rating-spam', 'x-rating-confirmed-spam', 'x-rating-passworded', 'x-rating-confirmed-passworded') class URLGrabber(Thread): do = None # Link to instance of the thread def __init__(self): Thread.__init__(self) self.queue = Queue.Queue() for tup in NzbQueue.do.get_urls(): url, nzo = tup self.queue.put((url, nzo)) self.shutdown = False URLGrabber.do = self def add(self, url, future_nzo, when=None): """ Add an URL to the URLGrabber queue, 'when' is seconds from now """ if future_nzo and when: # Always increase counter future_nzo.url_tries += 1 # Too many tries? Cancel if future_nzo.url_tries > MAX_URL_RETRIES: bad_fetch(future_nzo, url, T('Maximum retries')) return future_nzo.url_wait = time.time() + when self.queue.put((url, future_nzo)) def stop(self): logging.info('URLGrabber shutting down') self.shutdown = True self.add(None, None) def run(self): logging.info('URLGrabber starting up') self.shutdown = False while not self.shutdown: (url, future_nzo) = self.queue.get() if not url: # stop signal, go test self.shutdown continue if future_nzo: # Re-queue when too early and still active if future_nzo.url_wait and future_nzo.url_wait > time.time(): self.add(url, future_nzo) time.sleep(1.0) continue # Paused if future_nzo.status == Status.PAUSED: self.add(url, future_nzo) time.sleep(1.0) continue url = url.replace(' ', '') try: if future_nzo: # If nzo entry deleted, give up try: deleted = future_nzo.deleted except AttributeError: deleted = True if deleted: logging.debug('Dropping URL %s, job entry missing', url) continue filename = None category = None gzipped = False nzo_info = {} wait = 0 retry = True fn = None logging.info('Grabbing URL %s', url) try: fn = _build_request(url) except Exception, e: # Cannot list exceptions here, because of unpredictability over platforms error0 = str(sys.exc_info()[0]).lower() error1 = str(sys.exc_info()[1]).lower() logging.debug('Error "%s" trying to get the url %s', error1, url) if 'certificate_verify_failed' in error1 or 'certificateerror' in error0: msg = T('Server %s uses an untrusted HTTPS certificate') % '' msg += ' - https://sabnzbd.org/certificate-errors' retry = False elif 'nodename nor servname provided' in error1: msg = T('Server name does not resolve') retry = False elif '401' in error1 or 'unauthorized' in error1: msg = T('Unauthorized access') retry = False elif '404' in error1: msg = T('File not on server') retry = False elif hasattr(e, 'headers') and 'retry-after' in e.headers: # Catch if the server send retry (e.headers is case-INsensitive) wait = misc.int_conv(e.headers['retry-after']) new_url = dereferring(url, fn) if new_url: self.add(new_url, future_nzo) continue if fn: for hdr in fn.headers: try: item = hdr.lower() value = fn.headers[hdr] except: continue if item in ('content-encoding',) and value == 'gzip': gzipped = True if item in ('category_id', 'x-dnzb-category'): category = value elif item in ('x-dnzb-moreinfo',): nzo_info['more_info'] = value elif item in ('x-dnzb-name',): filename = value if not filename.endswith('.nzb'): filename += '.nzb' elif item == 'x-dnzb-propername': nzo_info['propername'] = value elif item == 'x-dnzb-episodename': nzo_info['episodename'] = value elif item == 'x-dnzb-year': nzo_info['year'] = value elif item == 'x-dnzb-failure': nzo_info['failure'] = value elif item == 'x-dnzb-details': nzo_info['details'] = value elif item == 'x-dnzb-password': nzo_info['password'] = value elif item == 'retry-after': wait = misc.int_conv(value) # Rating fields if item in _RARTING_FIELDS: nzo_info[item] = value if not filename and "filename=" in value: filename = value[value.index("filename=") + 9:].strip(';').strip('"') if wait: # For sites that have a rate-limiting attribute msg = '' retry = True fn = None elif retry: fn, msg, retry, wait, data = _analyse(fn, url, future_nzo) if not fn: if retry: logging.info('Retry URL %s', url) self.add(url, future_nzo, wait) else: bad_fetch(future_nzo, url, msg) continue if not filename: filename = os.path.basename(url) elif '&nzbname=' in filename: # Sometimes the filename contains the full URL, duh! filename = filename[filename.find('&nzbname=') + 9:] pp = future_nzo.pp script = future_nzo.script cat = future_nzo.cat if (cat is None or cat == '*') and category: cat = misc.cat_convert(category) priority = future_nzo.priority nzbname = future_nzo.custom_name # process data if gzipped: filename += '.gz' if not data: try: data = fn.read() except (IncompleteRead, IOError): bad_fetch(future_nzo, url, T('Server could not complete request')) fn.close() continue fn.close() if '') data = fn.read() for line in data.split('\n'): if ' 0: emailer.badfetch_mail(msg, url) NzbQueue.do.remove(nzo.nzo_id, add_to_history=True) SABnzbd-2.3.2/sabnzbd/version.py0000644000000000000000000000037113217005257014614 0ustar 00000000000000# This file will be patched by setup.py # The __version__ should be set to the branch name # (e.g. "develop" or "1.2.x") # You MUST use double quotes (so " and not ') __version__ = "2.3.2" __baseline__ = "1cac5799eb3f74f2e39942453b7b244fb0366e9a" SABnzbd-2.3.2/sabnzbd/wizard.py0000644000000000000000000002230013217005257014423 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.wizard - Wizard Webinterface """ import os import logging import cherrypy from Cheetah.Template import Template import sabnzbd import sabnzbd.api from sabnzbd.lang import list_languages, set_language from sabnzbd.api import Ttemplate import sabnzbd.interface import sabnzbd.config as config import sabnzbd.cfg as cfg class Wizard(object): def __init__(self, root): self.__root = root # Get the path for the folder named wizard self.__web_dir = sabnzbd.WIZARD_DIR self.info = {'webdir': sabnzbd.WIZARD_DIR, 'steps': 2, 'version': sabnzbd.__version__, 'T': T} @cherrypy.expose def index(self, **kwargs): """ Show the language selection page """ if cfg.configlock() or not sabnzbd.interface.check_access(): return sabnzbd.interface.Protected() if not sabnzbd.interface.check_login(): raise sabnzbd.interface.NeedLogin() info = self.info.copy() lng = None if sabnzbd.WIN32: import util.apireg lng = util.apireg.get_install_lng() logging.debug('Installer language code "%s"', lng) info['lang'] = lng or cfg.language() info['active_lang'] = info['lang'] info['languages'] = list_languages() info['T'] = Ttemplate set_language(info['lang']) sabnzbd.api.clear_trans_cache() if not os.path.exists(self.__web_dir): # If the wizard folder does not exist, simply load the normal page raise cherrypy.HTTPRedirect('') else: template = Template(file=os.path.join(self.__web_dir, 'index.html'), searchList=[info], compilerSettings=sabnzbd.interface.DIRECTIVES) return template.respond() @cherrypy.expose def exit(self, **kwargs): """ Stop SABnzbd """ if cfg.configlock() or not sabnzbd.interface.check_access(): return sabnzbd.interface.Protected() if not sabnzbd.interface.check_login(): raise sabnzbd.interface.NeedLogin() logging.info('Shutdown requested by wizard') sabnzbd.halt() cherrypy.engine.exit() sabnzbd.SABSTOP = True return T('SABnzbd shutdown finished') @cherrypy.expose def one(self, **kwargs): """ Accept language and show server page """ if cfg.configlock() or not sabnzbd.interface.check_access(): return sabnzbd.interface.Protected() if not sabnzbd.interface.check_login(): raise sabnzbd.interface.NeedLogin() language = kwargs.get('lang') if kwargs.get('lang') else cfg.language() cfg.language.set(language) set_language(language) sabnzbd.api.clear_trans_cache() # Always setup Glitter sabnzbd.interface.change_web_dir('Glitter - Default') info = self.info.copy() info['session'] = cfg.api_key() info['language'] = cfg.language() info['active_lang'] = info['language'] info['T'] = Ttemplate info['have_ssl_context'] = sabnzbd.HAVE_SSL_CONTEXT servers = config.get_servers() if not servers: info['host'] = '' info['port'] = '' info['username'] = '' info['password'] = '' info['connections'] = '' info['ssl'] = 0 info['ssl_verify'] = 2 else: # Sort servers to get the first enabled one server_names = sorted(servers.keys(), key=lambda svr: '%d%02d%s' % (int(not servers[svr].enable()), servers[svr].priority(), servers[svr].displayname().lower())) for server in server_names: # If there are multiple servers, just use the first enabled one s = servers[server] info['host'] = s.host() info['port'] = s.port() info['username'] = s.username() info['password'] = s.password.get_stars() info['connections'] = s.connections() info['ssl'] = s.ssl() info['ssl_verify'] = s.ssl_verify() if s.enable(): break template = Template(file=os.path.join(self.__web_dir, 'one.html'), searchList=[info], compilerSettings=sabnzbd.interface.DIRECTIVES) return template.respond() @cherrypy.expose def two(self, **kwargs): """ Accept server and show the final page for restart """ if cfg.configlock() or not sabnzbd.interface.check_access(): return sabnzbd.interface.Protected() if not sabnzbd.interface.check_login(): raise sabnzbd.interface.NeedLogin() # Save server details if kwargs: kwargs['enable'] = 1 sabnzbd.interface.handle_server(kwargs) config.save_config() # Show Restart screen info = self.info.copy() info['helpuri'] = 'https://sabnzbd.org/wiki/' info['session'] = cfg.api_key() info['access_url'], info['urls'] = self.get_access_info() info['active_lang'] = cfg.language() info['T'] = Ttemplate info['download_dir'] = cfg.download_dir.get_path() info['complete_dir'] = cfg.complete_dir.get_path() template = Template(file=os.path.join(self.__web_dir, 'two.html'), searchList=[info], compilerSettings=sabnzbd.interface.DIRECTIVES) return template.respond() def get_access_info(self): """ Build up a list of url's that sabnzbd can be accessed from """ # Access_url is used to provide the user a link to sabnzbd depending on the host access_uri = 'localhost' cherryhost = cfg.cherryhost() if cherryhost == '0.0.0.0': import socket host = socket.gethostname() socks = [host] # Grab a list of all ips for the hostname try: addresses = socket.getaddrinfo(host, None) except: addresses = [] for addr in addresses: address = addr[4][0] # Filter out ipv6 addresses (should not be allowed) if ':' not in address and address not in socks: socks.append(address) if "host" in cherrypy.request.headers: host = cherrypy.request.headers['host'] host = host.rsplit(':')[0] access_uri = host socks.insert(0, host) else: socks.insert(0, 'localhost') elif cherryhost == '::': import socket host = socket.gethostname() socks = [host] # Grab a list of all ips for the hostname addresses = socket.getaddrinfo(host, None) for addr in addresses: address = addr[4][0] # Only ipv6 addresses will work if ':' in address: address = '[%s]' % address if address not in socks: socks.append(address) if "host" in cherrypy.request.headers: host = cherrypy.request.headers['host'] host = host.rsplit(':')[0] access_uri = host socks.insert(0, host) else: socks.insert(0, 'localhost') elif not cherryhost: import socket socks = [socket.gethostname()] access_uri = socket.gethostname() else: socks = [cherryhost] access_uri = cherryhost urls = [] for sock in socks: if sock: if cfg.enable_https() and cfg.https_port(): url = 'https://%s:%s%s' % (sock, cfg.https_port(), cfg.url_base()) elif cfg.enable_https(): url = 'https://%s:%s%s' % (sock, cfg.cherryport(), cfg.url_base()) else: url = 'http://%s:%s%s' % (sock, cfg.cherryport(), cfg.url_base()) urls.append(url) if cfg.enable_https() and cfg.https_port(): access_url = 'https://%s:%s%s' % (sock, cfg.https_port(), cfg.url_base()) elif cfg.enable_https(): access_url = 'https://%s:%s%s' % (access_uri, cfg.cherryport(), cfg.url_base()) else: access_url = 'http://%s:%s%s' % (access_uri, cfg.cherryport(), cfg.url_base()) return access_url, urls SABnzbd-2.3.2/sabnzbd/zconfig.py0000644000000000000000000000752213217005257014573 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.zconfig - bonjour/zeroconfig support """ import os import logging import cherrypy _HOST_PORT = (None, None) try: from sabnzbd.utils import pybonjour from threading import Thread _HAVE_BONJOUR = True except: _HAVE_BONJOUR = False import sabnzbd import sabnzbd.cfg as cfg from sabnzbd.misc import match_str _BONJOUR_OBJECT = None def hostname(): """ Return host's pretty name """ if sabnzbd.WIN32: return os.environ.get('computername', 'unknown') try: return os.uname()[1] except: return 'unknown' def _zeroconf_callback(sdRef, flags, errorCode, name, regtype, domain): logging.debug('Full Bonjour-callback sdRef=%s, flags=%s, errorCode=%s, name=%s, regtype=%s, domain=%s', sdRef, flags, errorCode, name, regtype, domain) if errorCode == pybonjour.kDNSServiceErr_NoError: logging.info('Registered in Bonjour as "%s" (%s)', name, domain) def set_bonjour(host=None, port=None): """ Publish host/port combo through Bonjour """ global _HOST_PORT, _BONJOUR_OBJECT if not _HAVE_BONJOUR or not cfg.enable_bonjour(): logging.info('No Bonjour/ZeroConfig support installed') return if host is None and port is None: host, port = _HOST_PORT else: _HOST_PORT = (host, port) scope = pybonjour.kDNSServiceInterfaceIndexAny zhost = None domain = None if match_str(host, ('localhost', '127.0.', '::1')): logging.info('Bonjour/ZeroConfig does not support "localhost"') # All implementations fail to implement "localhost" properly # A false address is published even when scope==kDNSServiceInterfaceIndexLocalOnly return name = hostname() if '.local' in name: suffix = '' else: suffix = '.local' logging.debug('Try to publish in Bonjour as "%s" (%s:%s)', name, host, port) try: refObject = pybonjour.DNSServiceRegister( interfaceIndex=scope, name='SABnzbd on %s:%s' % (name, port), regtype='_http._tcp', domain=domain, host=zhost, port=int(port), txtRecord=pybonjour.TXTRecord({'path': cfg.url_base(), 'https': cfg.enable_https()}), callBack=_zeroconf_callback) except sabnzbd.utils.pybonjour.BonjourError as e: _BONJOUR_OBJECT = None logging.debug('Failed to start Bonjour service: %s', str(e)) except: _BONJOUR_OBJECT = None logging.debug('Failed to start Bonjour service due to non-pybonjour related problem', exc_info=True) else: Thread(target=_bonjour_server, args=(refObject,)) _BONJOUR_OBJECT = refObject logging.debug('Successfully started Bonjour service') def _bonjour_server(refObject): while 1: pybonjour.DNSServiceProcessResult(refObject) logging.debug('GOT A BONJOUR CALL') def remove_server(): """ Remove Bonjour registration """ global _BONJOUR_OBJECT if _BONJOUR_OBJECT: _BONJOUR_OBJECT.close() _BONJOUR_OBJECT = None SABnzbd-2.3.2/sabnzbd/__init__.py0000644000000000000000000010766313217005257014702 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Imported to be referenced from other files directly from sabnzbd.version import __version__, __baseline__ import os import logging import datetime import tempfile import cPickle import pickle import gzip import subprocess import time import socket import cherrypy import sys import re from threading import Lock, Thread try: import sleepless except ImportError: sleepless = None ############################################################################## # Determine platform flags ############################################################################## WIN32 = DARWIN = FOUNDATION = WIN64 = False KERNEL32 = None if os.name == 'nt': WIN32 = True from util.apireg import del_connection_info try: import ctypes KERNEL32 = ctypes.windll.LoadLibrary("Kernel32.dll") except: pass elif os.name == 'posix': ORG_UMASK = os.umask(18) os.umask(ORG_UMASK) import platform if platform.system().lower() == 'darwin': DARWIN = True # 12 = Sierra, 11 = ElCaptain, 10 = Yosemite, 9 = Mavericks, 8 = MountainLion DARWIN_VERSION = int(platform.mac_ver()[0].split('.')[1]) try: import Foundation FOUNDATION = True except: pass ############################################################################## # SSL CHECKS ############################################################################## import ssl HAVE_SSL_CONTEXT = None try: # Test availability of SSLContext (python 2.7.9+) ssl.SSLContext HAVE_SSL_CONTEXT = True except: HAVE_SSL_CONTEXT = False try: import cryptography HAVE_CRYPTOGRAPHY = cryptography.__version__ except: HAVE_CRYPTOGRAPHY = False # Now we can import safely from sabnzbd.nzbqueue import NzbQueue from sabnzbd.postproc import PostProcessor from sabnzbd.downloader import Downloader from sabnzbd.assembler import Assembler from sabnzbd.rating import Rating import sabnzbd.misc as misc import sabnzbd.powersup as powersup from sabnzbd.dirscanner import DirScanner, ProcessArchiveFile, ProcessSingleFile from sabnzbd.urlgrabber import URLGrabber import sabnzbd.scheduler as scheduler import sabnzbd.rss as rss import sabnzbd.emailer as emailer from sabnzbd.articlecache import ArticleCache import sabnzbd.newsunpack import sabnzbd.encoding as encoding import sabnzbd.config as config from sabnzbd.bpsmeter import BPSMeter import sabnzbd.cfg as cfg import sabnzbd.database import sabnzbd.lang as lang import sabnzbd.par2file as par2file import sabnzbd.api import sabnzbd.directunpacker as directunpacker from sabnzbd.decorators import synchronized from sabnzbd.constants import NORMAL_PRIORITY, VALID_ARCHIVES, \ REPAIR_REQUEST, QUEUE_FILE_NAME, QUEUE_VERSION, QUEUE_FILE_TMPL import sabnzbd.getipaddress as getipaddress LINUX_POWER = powersup.HAVE_DBUS START = datetime.datetime.now() MY_NAME = None MY_FULLNAME = None RESTART_ARGS = [] NEW_VERSION = (None, None) DIR_HOME = None DIR_APPDATA = None DIR_LCLDATA = None DIR_PROG = None DIR_INTERFACES = None DIR_LANGUAGE = None DIR_PID = None QUEUECOMPLETE = None # stores the nice name of the action QUEUECOMPLETEACTION = None # stores the name of the function to be called QUEUECOMPLETEARG = None # stores an extra arguments that need to be passed DAEMON = None LOGFILE = None WEBLOGFILE = None LOGHANDLER = None GUIHANDLER = None LOG_ALL = False AMBI_LOCALHOST = False WIN_SERVICE = None # Instance of our Win32 Service Class BROWSER_URL = None CMDLINE = '' # Rendering of original command line arguments WEB_DIR = None WEB_DIR_CONFIG = None WIZARD_DIR = None WEB_COLOR = None SABSTOP = False RESTART_REQ = False PAUSED_ALL = False OLD_QUEUE = False TRIGGER_RESTART = False # To trigger restart for Scheduler, WinService and Mac WINTRAY = None # Thread for the Windows SysTray icon WEBUI_READY = False LAST_WARNING = None LAST_ERROR = None EXTERNAL_IPV6 = False LAST_HISTORY_UPDATE = 1 # Performance measure for dashboard PYSTONE_SCORE = 0 DOWNLOAD_DIR_SPEED = 0 COMPLETE_DIR_SPEED = 0 __INITIALIZED__ = False __SHUTTING_DOWN__ = False ############################################################################## # Signal Handler ############################################################################## def sig_handler(signum=None, frame=None): global SABSTOP, WINTRAY if sabnzbd.WIN32 and signum is not None and DAEMON and signum == 5: # Ignore the "logoff" event when running as a Win32 daemon return True if signum is not None: logging.warning(T('Signal %s caught, saving and exiting...'), signum) try: save_state() sabnzbd.zconfig.remove_server() finally: if sabnzbd.WIN32: from util.apireg import del_connection_info del_connection_info() if sabnzbd.WINTRAY: sabnzbd.WINTRAY.terminate = True time.sleep(0.5) else: pid_file() SABSTOP = True os._exit(0) ############################################################################## # Initializing ############################################################################## INIT_LOCK = Lock() def connect_db(thread_index=0): # Create a connection and store it in the current thread if not (hasattr(cherrypy.thread_data, 'history_db') and cherrypy.thread_data.history_db): cherrypy.thread_data.history_db = sabnzbd.database.HistoryDB() return cherrypy.thread_data.history_db @synchronized(INIT_LOCK) def initialize(pause_downloader=False, clean_up=False, evalSched=False, repair=0): global __INITIALIZED__, __SHUTTING_DOWN__,\ LOGFILE, WEBLOGFILE, LOGHANDLER, GUIHANDLER, AMBI_LOCALHOST, WAITEXIT, \ DAEMON, MY_NAME, MY_FULLNAME, NEW_VERSION, \ DIR_HOME, DIR_APPDATA, DIR_LCLDATA, DIR_PROG, DIR_INTERFACES, \ DARWIN, RESTART_REQ, OLD_QUEUE if __INITIALIZED__: return False __SHUTTING_DOWN__ = False # Set global database connection for Web-UI threads cherrypy.engine.subscribe('start_thread', connect_db) # Paused? pause_downloader = pause_downloader or cfg.start_paused() # Clean-up, if requested if clean_up: # New admin folder misc.remove_all(cfg.admin_dir.get_path(), '*.sab') # Optionally wait for "incomplete" to become online if cfg.wait_for_dfolder(): wait_for_download_folder() else: cfg.download_dir.set(cfg.download_dir(), create=True) cfg.download_dir.set_create(True) # Set access rights for "incomplete" base folder misc.set_permissions(cfg.download_dir.get_path(), recursive=False) # If dirscan_dir cannot be created, set a proper value anyway. # Maybe it's a network path that's temporarily missing. path = cfg.dirscan_dir.get_path() if not os.path.exists(path): sabnzbd.misc.create_real_path(cfg.dirscan_dir.ident(), '', path, False) # Set call backs for Config items cfg.cache_limit.callback(new_limit) cfg.cherryhost.callback(guard_restart) cfg.cherryport.callback(guard_restart) cfg.web_dir.callback(guard_restart) cfg.web_color.callback(guard_restart) cfg.username.callback(guard_restart) cfg.password.callback(guard_restart) cfg.log_dir.callback(guard_restart) cfg.https_port.callback(guard_restart) cfg.https_cert.callback(guard_restart) cfg.https_key.callback(guard_restart) cfg.enable_https.callback(guard_restart) cfg.top_only.callback(guard_top_only) cfg.pause_on_post_processing.callback(guard_pause_on_pp) cfg.growl_server.callback(sabnzbd.notifier.change_value) cfg.growl_password.callback(sabnzbd.notifier.change_value) cfg.quota_size.callback(guard_quota_size) cfg.quota_day.callback(guard_quota_dp) cfg.quota_period.callback(guard_quota_dp) cfg.fsys_type.callback(guard_fsys_type) cfg.language.callback(sabnzbd.notifier.reset_growl) cfg.enable_https_verification.callback(guard_https_ver) guard_https_ver() # Set Posix filesystem encoding sabnzbd.encoding.change_fsys(cfg.fsys_type()) # Set cache limit if not cfg.cache_limit() or (cfg.cache_limit() in ('200M', '450M') and (sabnzbd.WIN32 or sabnzbd.DARWIN)): cfg.cache_limit.set(misc.get_cache_limit()) ArticleCache.do.new_limit(cfg.cache_limit.get_int()) check_incomplete_vs_complete() # Set language files lang.set_locale_info('SABnzbd', DIR_LANGUAGE) lang.set_language(cfg.language()) sabnzbd.api.clear_trans_cache() OLD_QUEUE = check_old_queue() sabnzbd.change_queue_complete_action(cfg.queue_complete(), new=False) # One time conversion "speedlimit" in schedules. if not cfg.sched_converted(): schedules = cfg.schedules() newsched = [] for sched in schedules: if 'speedlimit' in sched: newsched.append(re.sub(r'(speedlimit \d+)$', r'\1K', sched)) else: newsched.append(sched) cfg.schedules.set(newsched) cfg.sched_converted.set(1) # Second time schedule conversion if cfg.sched_converted() != 2: cfg.schedules.set(['%s %s' % (1, schedule) for schedule in cfg.schedules()]) cfg.sched_converted.set(2) config.save_config() if check_repair_request(): repair = 2 pause_downloader = True # Initialize threads rss.init() paused = BPSMeter.do.read() NzbQueue() Downloader(pause_downloader or paused) Assembler() PostProcessor() NzbQueue.do.read_queue(repair) DirScanner() Rating() URLGrabber() scheduler.init() if evalSched: scheduler.analyse(pause_downloader) logging.info('All processes started') RESTART_REQ = False __INITIALIZED__ = True return True @synchronized(INIT_LOCK) def start(): global __INITIALIZED__ if __INITIALIZED__: logging.debug('Starting postprocessor') PostProcessor.do.start() logging.debug('Starting assembler') Assembler.do.start() logging.debug('Starting downloader') Downloader.do.start() scheduler.start() logging.debug('Starting dirscanner') DirScanner.do.start() Rating.do.start() logging.debug('Starting urlgrabber') URLGrabber.do.start() @synchronized(INIT_LOCK) def halt(): global __INITIALIZED__, __SHUTTING_DOWN__ if __INITIALIZED__: logging.info('SABnzbd shutting down...') __SHUTTING_DOWN__ = True # Stop the windows tray icon if sabnzbd.WINTRAY: sabnzbd.WINTRAY.terminate = True sabnzbd.zconfig.remove_server() sabnzbd.directunpacker.abort_all() rss.stop() logging.debug('Stopping URLGrabber') URLGrabber.do.stop() try: URLGrabber.do.join() except: pass logging.debug('Stopping rating') Rating.do.stop() try: Rating.do.join() except: pass logging.debug('Stopping dirscanner') DirScanner.do.stop() try: DirScanner.do.join() except: pass # Stop Required Objects logging.debug('Stopping downloader') sabnzbd.downloader.stop() logging.debug('Stopping assembler') Assembler.do.stop() try: Assembler.do.join() except: pass logging.debug('Stopping postprocessor') PostProcessor.do.stop() try: PostProcessor.do.join() except: pass # Save State try: save_state() except: logging.error(T('Fatal error at saving state'), exc_info=True) # The Scheduler cannot be stopped when the stop was scheduled. # Since all warm-restarts have been removed, it's not longer # needed to stop the scheduler. # We must tell the scheduler to deactivate. scheduler.abort() logging.info('All processes stopped') __INITIALIZED__ = False def trigger_restart(timeout=None): """ Trigger a restart by setting a flag an shutting down CP """ # Sometimes we need to wait a bit to send good-bye to the browser if timeout: time.sleep(timeout) # Add extra arguments if sabnzbd.downloader.Downloader.do.paused: sabnzbd.RESTART_ARGS.append('-p') sys.argv = sabnzbd.RESTART_ARGS # Stop all services sabnzbd.halt() cherrypy.engine.exit() if sabnzbd.WIN32: # Remove connection info for faster restart del_connection_info() # Leave the harder restarts to the polling in SABnzbd.py if sabnzbd.WIN_SERVICE or getattr(sys, 'frozen', None) == 'macosx_app': sabnzbd.TRIGGER_RESTART = True else: # Do the restart right now cherrypy.engine._do_execv() ############################################################################## # Misc Wrappers ############################################################################## def new_limit(): """ Callback for article cache changes """ ArticleCache.do.new_limit(cfg.cache_limit.get_int()) def guard_restart(): """ Callback for config options requiring a restart """ global RESTART_REQ sabnzbd.RESTART_REQ = True def guard_top_only(): """ Callback for change of top_only option """ NzbQueue.do.set_top_only(cfg.top_only()) def guard_pause_on_pp(): """ Callback for change of pause-download-on-pp """ if cfg.pause_on_post_processing(): pass # Not safe to idle downloader, because we don't know # if post-processing is active now else: Downloader.do.resume_from_postproc() def guard_quota_size(): """ Callback for change of quota_size """ BPSMeter.do.change_quota() def guard_quota_dp(): """ Callback for change of quota_day or quota_period """ scheduler.restart(force=True) def guard_fsys_type(): """ Callback for change of file system naming type """ sabnzbd.encoding.change_fsys(cfg.fsys_type()) def set_https_verification(value): prev = False try: import ssl if hasattr(ssl, '_create_default_https_context'): prev = ssl._create_default_https_context == ssl.create_default_context if value: ssl._create_default_https_context = ssl.create_default_context else: ssl._create_default_https_context = ssl._create_unverified_context except ImportError: pass return prev def guard_https_ver(): """ Callback for change of https verification """ set_https_verification(cfg.enable_https_verification()) def add_url(url, pp=None, script=None, cat=None, priority=None, nzbname=None): """ Add NZB based on a URL, attributes optional """ if 'http' not in url: return if not pp or pp == "-1": pp = None if script and script.lower() == 'default': script = None if cat and cat.lower() == 'default': cat = None logging.info('Fetching %s', url) # Add feed name if it came from RSS msg = T('Trying to fetch NZB from %s') % url if nzbname: msg = '%s - %s' % (nzbname, msg) # Generate the placeholder future_nzo = NzbQueue.do.generate_future(msg, pp, script, cat, url=url, priority=priority, nzbname=nzbname) URLGrabber.do.add(url, future_nzo) return future_nzo.nzo_id def save_state(): """ Save all internal bookkeeping to disk """ ArticleCache.do.flush_articles() NzbQueue.do.save() BPSMeter.do.save() rss.save() Rating.do.save() DirScanner.do.save() PostProcessor.do.save() def pause_all(): """ Pause all activities than cause disk access """ global PAUSED_ALL PAUSED_ALL = True Downloader.do.pause() logging.debug('PAUSED_ALL active') def unpause_all(): """ Resume all activities """ global PAUSED_ALL PAUSED_ALL = False Downloader.do.resume() logging.debug('PAUSED_ALL inactive') ############################################################################## # NZB Saving Methods ############################################################################## def backup_exists(filename): """ Return True if backup exists and no_dupes is set """ path = cfg.nzb_backup_dir.get_path() return path and os.path.exists(os.path.join(path, filename + '.gz')) def backup_nzb(filename, data): """ Backup NZB file """ path = cfg.nzb_backup_dir.get_path() if path: save_compressed(path, filename, data) def save_compressed(folder, filename, data): """ Save compressed NZB file in folder """ if filename.endswith('.nzb'): filename += '.gz' else: filename += '.nzb.gz' logging.info("Backing up %s", os.path.join(folder, filename)) try: # Have to get around the path being put inside the tgz with open(os.path.join(folder, filename), 'wb') as tgz_file: f = gzip.GzipFile(filename, fileobj=tgz_file) f.write(data) f.flush() f.close() except: logging.error(T('Saving %s failed'), os.path.join(folder, filename)) logging.info("Traceback: ", exc_info=True) ############################################################################## # Unsynchronized methods ############################################################################## def add_nzbfile(nzbfile, pp=None, script=None, cat=None, priority=NORMAL_PRIORITY, nzbname=None, reuse=False, password=None): """ Add disk-based NZB file, optional attributes, 'reuse' flag will suppress duplicate detection """ if pp and pp == "-1": pp = None if script and script.lower() == 'default': script = None if cat and cat.lower() == 'default': cat = None if isinstance(nzbfile, basestring): # File coming from queue repair filename = nzbfile keep = True else: # File coming from API/TAPI # Consider reception of Latin-1 names for non-Windows platforms # When an OSX/Unix server receives a file from Windows platform # CherryPy delivers filename as UTF-8 disguised as Unicode! try: filename = nzbfile.filename.encode('cp1252').decode('utf-8') except: # Correct encoding afterall! filename = nzbfile.filename filename = encoding.special_fixer(filename) keep = False if not sabnzbd.WIN32: # If windows client sends file to Unix server backslashed may # be included, so convert these filename = filename.replace('\\', '/') filename = os.path.basename(filename) ext = os.path.splitext(filename)[1] if ext.lower() in VALID_ARCHIVES: suffix = ext.lower() else: suffix = '.nzb' logging.info('Adding %s', filename) if isinstance(nzbfile, basestring): path = nzbfile else: try: f, path = tempfile.mkstemp(suffix=suffix, text=False) # More CherryPy madness, sometimes content is in 'value', sometimes not. if nzbfile.value: os.write(f, nzbfile.value) elif hasattr(nzbfile, 'file'): # CherryPy 3.2.2 object if hasattr(nzbfile.file, 'file'): os.write(f, nzbfile.file.file.read()) else: os.write(f, nzbfile.file.read()) os.close(f) except: logging.error(T('Cannot create temp file for %s'), filename) logging.info("Traceback: ", exc_info=True) if ext.lower() in VALID_ARCHIVES: return ProcessArchiveFile(filename, path, pp, script, cat, priority=priority, nzbname=nzbname, password=password) else: return ProcessSingleFile(filename, path, pp, script, cat, priority=priority, nzbname=nzbname, keep=keep, reuse=reuse, password=password) def enable_server(server): """ Enable server (scheduler only) """ try: config.get_config('servers', server).enable.set(1) except: logging.warning(T('Trying to set status of non-existing server %s'), server) return config.save_config() Downloader.do.update_server(server, server) def disable_server(server): """ Disable server (scheduler only) """ try: config.get_config('servers', server).enable.set(0) except: logging.warning(T('Trying to set status of non-existing server %s'), server) return config.save_config() Downloader.do.update_server(server, server) def system_shutdown(): """ Shutdown system after halting download and saving bookkeeping """ logging.info("Performing system shutdown") Thread(target=halt).start() while __INITIALIZED__: time.sleep(1.0) if sabnzbd.WIN32: powersup.win_shutdown() elif DARWIN: powersup.osx_shutdown() else: powersup.linux_shutdown() def system_hibernate(): """ Hibernate system """ logging.info("Performing system hybernation") if sabnzbd.WIN32: powersup.win_hibernate() elif DARWIN: powersup.osx_hibernate() else: powersup.linux_hibernate() def system_standby(): """ Standby system """ logging.info("Performing system standby") if sabnzbd.WIN32: powersup.win_standby() elif DARWIN: powersup.osx_standby() else: powersup.linux_standby() def shutdown_program(): """ Stop program after halting and saving """ logging.info("Performing sabnzbd shutdown") sabnzbd.halt() cherrypy.engine.exit() sabnzbd.SABSTOP = True def restart_program(): """ Restart program (used by scheduler) """ logging.info("Scheduled restart request") # Just set the stop flag, because stopping CherryPy from # the scheduler is not reliable sabnzbd.TRIGGER_RESTART = True def change_queue_complete_action(action, new=True): """ Action or script to be performed once the queue has been completed Scripts are prefixed with 'script_' When "new" is False, check whether non-script actions are acceptable """ global QUEUECOMPLETE, QUEUECOMPLETEACTION, QUEUECOMPLETEARG _action = None _argument = None if 'script_' in action: # all scripts are labeled script_xxx _action = run_script _argument = action.replace('script_', '') elif new or cfg.queue_complete_pers.get(): if action == 'shutdown_pc': _action = system_shutdown elif action == 'hibernate_pc': _action = system_hibernate elif action == 'standby_pc': _action = system_standby elif action == 'shutdown_program': _action = shutdown_program else: action = None else: action = None if new: cfg.queue_complete.set(action or '') config.save_config() # keep the name of the action for matching the current select in queue.tmpl QUEUECOMPLETE = action QUEUECOMPLETEACTION = _action QUEUECOMPLETEARG = _argument def run_script(script): """ Run a user script (queue complete only) """ command = [os.path.join(cfg.script_dir.get_path(), script)] if os.path.exists(command[0]): try: stup, need_shell, command, creationflags = sabnzbd.newsunpack.build_command(command) logging.info('Spawning external command %s', command) subprocess.Popen(command, shell=need_shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=stup, creationflags=creationflags) except: logging.debug("Failed script %s, Traceback: ", script, exc_info=True) def empty_queues(): """ Return True if queues empty or non-existent """ global __INITIALIZED__ return (not __INITIALIZED__) or (PostProcessor.do.empty() and NzbQueue.do.is_empty()) def keep_awake(): """ If we still have work to do, keep Windows/OSX system awake """ if KERNEL32 or sleepless: if sabnzbd.cfg.keep_awake(): awake = False if not sabnzbd.downloader.Downloader.do.paused: if (not PostProcessor.do.empty()) or not NzbQueue.do.is_empty(): awake = True if KERNEL32: # set ES_SYSTEM_REQUIRED KERNEL32.SetThreadExecutionState(ctypes.c_int(0x00000001)) else: sleepless.keep_awake(u'SABnzbd is busy downloading and/or post-processing') if not awake and sleepless: sleepless.allow_sleep() ################################################################################ # Data IO # ################################################################################ def get_new_id(prefix, folder, check_list=None): """ Return unique prefixed admin identifier within folder optionally making sure that id is not in the check_list. """ for n in xrange(10000): try: if not os.path.exists(folder): os.makedirs(folder) fd, path = tempfile.mkstemp('', 'SABnzbd_%s_' % prefix, folder) os.close(fd) head, tail = os.path.split(path) if not check_list or tail not in check_list: return tail except: logging.error(T('Failure in tempfile.mkstemp')) logging.info("Traceback: ", exc_info=True) break # Cannot create unique id, crash the process raise IOError def save_data(data, _id, path, do_pickle=True, silent=False): """ Save data to a diskfile """ if not silent: logging.debug('[%s] Saving data for %s in %s', misc.caller_name(), _id, path) path = os.path.join(path, _id) # We try 3 times, to avoid any dict or access problems for t in xrange(3): try: with open(path, 'wb') as data_file: if do_pickle: if cfg.use_pickle(): pickle.dump(data, data_file) else: cPickle.dump(data, data_file) else: data_file.write(data) break except: if silent: # This can happen, probably a removed folder pass elif t == 2: logging.error(T('Saving %s failed'), path) logging.info("Traceback: ", exc_info=True) else: # Wait a tiny bit before trying again time.sleep(0.1) def load_data(_id, path, remove=True, do_pickle=True, silent=False): """ Read data from disk file """ path = os.path.join(path, _id) if not os.path.exists(path): logging.info("[%s] %s missing", misc.caller_name(), path) return None if not silent: logging.debug("[%s] Loading data for %s from %s", misc.caller_name(), _id, path) try: with open(path, 'rb') as data_file: if do_pickle: if cfg.use_pickle(): data = pickle.load(data_file) else: data = cPickle.load(data_file) else: data = data_file.read() if remove: misc.remove_file(path) except: logging.error(T('Loading %s failed'), path) logging.info("Traceback: ", exc_info=True) return None return data def remove_data(_id, path): """ Remove admin file """ path = os.path.join(path, _id) try: if os.path.exists(path): misc.remove_file(path) except: logging.debug("Failed to remove %s", path) def save_admin(data, _id): """ Save data in admin folder in specified format """ path = os.path.join(cfg.admin_dir.get_path(), _id) logging.debug("[%s] Saving data for %s in %s", misc.caller_name(), _id, path) # We try 3 times, to avoid any dict or access problems for t in xrange(3): try: with open(path, 'wb') as data_file: if cfg.use_pickle(): data = pickle.dump(data, data_file) else: data = cPickle.dump(data, data_file) break except: if t == 2: logging.error(T('Saving %s failed'), path) logging.info("Traceback: ", exc_info=True) else: # Wait a tiny bit before trying again time.sleep(0.1) def load_admin(_id, remove=False, silent=False): """ Read data in admin folder in specified format """ path = os.path.join(cfg.admin_dir.get_path(), _id) logging.debug("[%s] Loading data for %s from %s", misc.caller_name(), _id, path) if not os.path.exists(path): logging.info("[%s] %s missing", misc.caller_name(), path) return None try: with open(path, 'rb') as data_file: if cfg.use_pickle(): data = pickle.load(data_file) else: data = cPickle.load(data_file) if remove: misc.remove_file(path) except: if not silent: excepterror = str(sys.exc_info()[0]) logging.error(T('Loading %s failed with error %s'), path, excepterror) logging.info("Traceback: ", exc_info=True) return None return data def pp_to_opts(pp): """ Convert numeric processing options to (repair, unpack, delete) """ # Convert the pp to an int pp = sabnzbd.interface.int_conv(pp) if pp == 0: return (False, False, False) if pp == 1: return (True, False, False) if pp == 2: return (True, True, False) return (True, True, True) def opts_to_pp(repair, unpack, delete): """ Convert (repair, unpack, delete) to numeric process options """ if repair is None: return None pp = 0 if repair: pp = 1 if unpack: pp = 2 if delete: pp = 3 return pp def request_repair(): """ Request a full repair on next restart """ path = os.path.join(cfg.admin_dir.get_path(), REPAIR_REQUEST) try: f = open(path, 'w') f.write('\n') f.close() except: pass def check_repair_request(): """ Return True if repair request found, remove afterwards """ path = os.path.join(cfg.admin_dir.get_path(), REPAIR_REQUEST) if os.path.exists(path): try: misc.remove_file(path) except: pass return True return False def check_all_tasks(): """ Check every task and restart safe ones, else restart program Return True when everything is under control """ if __SHUTTING_DOWN__ or not __INITIALIZED__: return True # Non-restartable threads, require program restart if not sabnzbd.PostProcessor.do.isAlive(): logging.info('Restarting because of crashed postprocessor') return False if not Downloader.do.isAlive(): logging.info('Restarting because of crashed downloader') return False if not Assembler.do.isAlive(): logging.info('Restarting because of crashed assembler') return False # Kick the downloader, in case it missed the semaphore Downloader.do.wakeup() # Make sure the right servers are active Downloader.do.check_timers() # Restartable threads if not DirScanner.do.isAlive(): logging.info('Restarting crashed dirscanner') DirScanner.do.__init__() if not URLGrabber.do.isAlive(): logging.info('Restarting crashed urlgrabber') URLGrabber.do.__init__() if not Rating.do.isAlive(): logging.info('Restarting crashed rating') Rating.do.__init__() if not sabnzbd.scheduler.sched_check(): logging.info('Restarting crashed scheduler') sabnzbd.scheduler.init() sabnzbd.downloader.Downloader.do.unblock_all() # Check one-shot pause sabnzbd.scheduler.pause_check() # Check (and terminate) idle jobs sabnzbd.nzbqueue.NzbQueue.do.stop_idle_jobs() return True def pid_file(pid_path=None, pid_file=None, port=0): """ Create or remove pid file """ global DIR_PID if not sabnzbd.WIN32: if pid_path and pid_path.startswith('/'): DIR_PID = os.path.join(pid_path, 'sabnzbd-%s.pid' % port) elif pid_file and pid_file.startswith('/'): DIR_PID = pid_file if DIR_PID: try: if port: f = open(DIR_PID, 'w') f.write('%d\n' % os.getpid()) f.close() else: misc.remove_file(DIR_PID) except: logging.warning('Cannot access PID file %s', DIR_PID) def check_incomplete_vs_complete(): """ Make sure "incomplete" and "complete" are not identical """ complete = cfg.complete_dir.get_path() if misc.same_file(cfg.download_dir.get_path(), complete): if misc.real_path('X', cfg.download_dir()) == cfg.download_dir(): # Abs path, so set an abs path too cfg.download_dir.set(os.path.join(complete, 'incomplete')) else: cfg.download_dir.set('incomplete') def wait_for_download_folder(): """ Wait for download folder to become available """ while not cfg.download_dir.test_path(): logging.debug('Waiting for "incomplete" folder') time.sleep(2.0) def check_old_queue(): """ Check for old queue (when a new queue is not present) """ old = False if not os.path.exists(os.path.join(cfg.admin_dir.get_path(), QUEUE_FILE_NAME)): for ver in (QUEUE_VERSION - 1, QUEUE_VERSION - 2, QUEUE_VERSION - 3): data = load_admin(QUEUE_FILE_TMPL % str(ver)) if data: break try: old = bool(data and isinstance(data, tuple) and len(data[1])) except (TypeError, IndexError): pass if old and sabnzbd.WIN32 and ver < 10 and sabnzbd.DIR_LCLDATA != sabnzbd.DIR_HOME and misc.is_relative_path(cfg.download_dir()): # For Windows and when version < 10: adjust old default location cfg.download_dir.set('Documents/' + cfg.download_dir()) return old # Required wrapper because nzbstuff.py cannot import downloader.py def highest_server(me): return sabnzbd.downloader.Downloader.do.highest_server(me) def test_ipv6(): """ Check if external IPv6 addresses are reachable """ if not cfg.selftest_host(): # User disabled the test, assume active IPv6 return True try: info = getipaddress.addresslookup6(cfg.selftest_host()) except: logging.debug("Test IPv6: Disabling IPv6, because it looks like it's not available. Reason: %s", sys.exc_info()[0] ) return False try: af, socktype, proto, canonname, sa = info[0] sock = socket.socket(af, socktype, proto) sock.settimeout(2) # 2 second timeout sock.connect(sa[0:2]) sock.close() logging.debug('Test IPv6: IPv6 test successful. Enabling IPv6') return True except socket.error: logging.debug('Test IPv6: Cannot reach IPv6 test host. Disabling IPv6') return False except: logging.debug('Test IPv6: Problem during IPv6 connect. Disabling IPv6. Reason: %s', sys.exc_info()[0]) return False def history_updated(): """ To make sure we always have a fresh history """ sabnzbd.LAST_HISTORY_UPDATE += 1 # Never go over the limit if sabnzbd.LAST_HISTORY_UPDATE+1 >= sys.maxint: sabnzbd.LAST_HISTORY_UPDATE = 1 SABnzbd-2.3.2/sabnzbd/utils/certgen.py0000644000000000000000000000622313217005257015720 0ustar 00000000000000#!/usr/bin/env python """ Adapted from the docs of cryptography Creates a key and self-signed certificate for local use """ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import rsa from cryptography import x509 from cryptography.x509.oid import NameOID import datetime import os from sabnzbd.getipaddress import localipv4 # Ported from cryptography/utils.py def int_from_bytes(data, byteorder, signed=False): assert byteorder == 'big' assert not signed # call bytes() on data to allow the use of bytearrays return int(bytes(data).encode('hex'), 16) # Ported from cryptography/x509/base.py def random_serial_number(): return int_from_bytes(os.urandom(20), "big") >> 1 # Ported from cryptography docs/x509/tutorial.rst (set with no encryption) def generate_key(key_size=2048, output_file='key.pem'): # Generate our key private_key = rsa.generate_private_key( public_exponent=65537, key_size=key_size, backend=default_backend() ) # Write our key to disk for safe keeping with open(output_file, "wb") as f: f.write(private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption() # encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase") )) return private_key # Ported from cryptography docs/x509/tutorial.rst def generate_local_cert(private_key, days_valid=3560, output_file='cert.cert', LN=u'SABnzbd', ON=u'SABnzbd', CN=u'localhost'): # Various details about who we are. For a self-signed certificate the # subject and issuer are always the same. subject = issuer = x509.Name([ x509.NameAttribute(NameOID.LOCALITY_NAME, LN), x509.NameAttribute(NameOID.ORGANIZATION_NAME, ON), # x509.NameAttribute(NameOID.COMMON_NAME, CN), ]) # build SubjectAltName list since we are not using a common name san_list = [ x509.DNSName(u"localhost"), x509.DNSName(u"127.0.0.1"), ] # append local v4 ip (functions already has try/catch logic) mylocalipv4 = localipv4() if mylocalipv4: san_list.append(x509.DNSName(u"" + mylocalipv4)) cert = x509.CertificateBuilder().subject_name( subject ).issuer_name( issuer ).public_key( private_key.public_key() ).not_valid_before( datetime.datetime.utcnow() ).not_valid_after( datetime.datetime.utcnow() + datetime.timedelta(days=days_valid) ).serial_number( random_serial_number() ).add_extension( x509.SubjectAlternativeName(san_list), critical=True, ).sign(private_key, hashes.SHA256(), default_backend()) # Write our certificate out to disk. with open(output_file, "wb") as f: f.write(cert.public_bytes(serialization.Encoding.PEM)) return cert if __name__ == '__main__': print 'Making key' private_key = generate_key() print 'Making cert' cert = generate_local_cert(private_key) SABnzbd-2.3.2/sabnzbd/utils/checkdir.py0000644000000000000000000000664113217005257016051 0ustar 00000000000000#!/usr/bin/env python """ Functions to check if the path filesystem uses FAT """ import sys import os import subprocess debug = False def isFAT(dir): # Check if "dir" is on FAT. FAT considered harmful (for big files) # Works for Linux, Windows, MacOS # NB: On Windows, full path with drive letter is needed! FAT = False # default: not FAT # We're dealing with OS calls, so put everything in a try/except, just in case: try: if 'linux' in sys.platform: # On Linux: # df -T /home/sander/weg ''' Example output of a 500GB external USB drive formatted with FAT: $ df -T /media/sander/INTENSO Filesystem Type 1K-blocks Used Available Use% Mounted on /dev/sda1 vfat 488263616 163545248 324718368 34% /media/sander/INTENSO ''' cmd = "df -T " + dir + " 2>&1" for thisline in os.popen(cmd).readlines(): #print thisline if thisline.find('/') == 0: # Starts with /, so a real, local device fstype = thisline.split()[1] if debug: print "File system type:", fstype if fstype.lower().find('fat') >= 0: FAT = True if debug: print "FAT found" break elif 'win32' in sys.platform: import win32api if '?' in dir: # Remove \\?\ or \\?\UNC\ prefix from Windows path dir = dir.replace(u'\\\\?\\UNC\\', u'\\\\', 1).replace(u'\\\\?\\', u'', 1) try: result = win32api.GetVolumeInformation(os.path.splitdrive(dir)[0]) if debug: print result if(result[4].startswith("FAT")): FAT = True except: pass elif 'darwin' in sys.platform: # MacOS formerly known as OSX ''' MacOS needs a two-step approach: # First: directory => device server:~ sander$ df /Volumes/CARTUNES/Tuna/ Filesystem 512-blocks Used Available Capacity iused ifree %iused Mounted on /dev/disk9s1 120815744 108840000 11975744 91% 0 0 100% /Volumes/CARTUNES # Then: device => filesystem type server:~ sander$ mount | grep /dev/disk9s1 /dev/disk9s1 on /Volumes/CARTUNES (msdos, local, nodev, nosuid, noowners) ''' dfcmd = "df " + dir device = '' for thisline in os.popen(dfcmd).readlines(): if thisline.find('/')==0: if debug: print thisline # Starts with /, so a real, local device device = thisline.split()[0] mountcmd = "mount | grep " + device mountoutput = os.popen(mountcmd).readline().strip() if debug: print mountoutput if 'msdos' in mountoutput.split('(')[1]: FAT = True break except: pass return FAT if __name__ == "__main__": if debug: print sys.platform try: dir = sys.argv[1] except: print "Specify dir on the command line" sys.exit(0) if isFAT(dir): print dir, "is on FAT" else: print dir, "is not on FAT" SABnzbd-2.3.2/sabnzbd/utils/configobj.py0000644000000000000000000025114613217005257016237 0ustar 00000000000000# configobj.py # A config file reader/writer that supports nested sections in config files. # Copyright (C) 2005-2010 Michael Foord, Nicola Larosa # E-mail: fuzzyman AT voidspace DOT org DOT uk # nico AT tekNico DOT net # ConfigObj 4 # http://www.voidspace.org.uk/python/configobj.html # Released subject to the BSD License # Please see http://www.voidspace.org.uk/python/license.shtml # Scripts maintained at http://www.voidspace.org.uk/python/index.shtml # For information about bugfixes, updates and support, please join the # ConfigObj mailing list: # http://lists.sourceforge.net/lists/listinfo/configobj-develop # Comments, suggestions and bug reports welcome. from __future__ import generators import os import re import sys from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE # imported lazily to avoid startup performance hit if it isn't used compiler = None # A dictionary mapping BOM to # the encoding to decode with, and what to set the # encoding attribute to. BOMS = { BOM_UTF8: ('utf_8', None), BOM_UTF16_BE: ('utf16_be', 'utf_16'), BOM_UTF16_LE: ('utf16_le', 'utf_16'), BOM_UTF16: ('utf_16', 'utf_16'), } # All legal variants of the BOM codecs. # TODO: the list of aliases is not meant to be exhaustive, is there a # better way ? BOM_LIST = { 'utf_16': 'utf_16', 'u16': 'utf_16', 'utf16': 'utf_16', 'utf-16': 'utf_16', 'utf16_be': 'utf16_be', 'utf_16_be': 'utf16_be', 'utf-16be': 'utf16_be', 'utf16_le': 'utf16_le', 'utf_16_le': 'utf16_le', 'utf-16le': 'utf16_le', 'utf_8': 'utf_8', 'u8': 'utf_8', 'utf': 'utf_8', 'utf8': 'utf_8', 'utf-8': 'utf_8', } # Map of encodings to the BOM to write. BOM_SET = { 'utf_8': BOM_UTF8, 'utf_16': BOM_UTF16, 'utf16_be': BOM_UTF16_BE, 'utf16_le': BOM_UTF16_LE, None: BOM_UTF8 } def match_utf8(encoding): return BOM_LIST.get(encoding.lower()) == 'utf_8' # Quote strings used for writing values squot = "'%s'" dquot = '"%s"' noquot = "%s" wspace_plus = ' \r\n\v\t\'"' tsquot = '"""%s"""' tdquot = "'''%s'''" # Sentinel for use in getattr calls to replace hasattr MISSING = object() __version__ = '4.7.2' try: any except NameError: def any(iterable): for entry in iterable: if entry: return True return False __all__ = ( '__version__', 'DEFAULT_INDENT_TYPE', 'DEFAULT_INTERPOLATION', 'ConfigObjError', 'NestingError', 'ParseError', 'DuplicateError', 'ConfigspecError', 'ConfigObj', 'SimpleVal', 'InterpolationError', 'InterpolationLoopError', 'MissingInterpolationOption', 'RepeatSectionError', 'ReloadError', 'UnreprError', 'UnknownType', 'flatten_errors', 'get_extra_values' ) DEFAULT_INTERPOLATION = 'configparser' DEFAULT_INDENT_TYPE = ' ' MAX_INTERPOL_DEPTH = 10 OPTION_DEFAULTS = { 'interpolation': True, 'raise_errors': False, 'list_values': True, 'create_empty': False, 'file_error': False, 'configspec': None, 'stringify': True, # option may be set to one of ('', ' ', '\t') 'indent_type': None, 'encoding': None, 'default_encoding': None, 'unrepr': False, 'write_empty_values': False, } def getObj(s): global compiler if compiler is None: import compiler s = "a=" + s p = compiler.parse(s) return p.getChildren()[1].getChildren()[0].getChildren()[1] class UnknownType(Exception): pass class Builder(object): def build(self, o): m = getattr(self, 'build_' + o.__class__.__name__, None) if m is None: raise UnknownType(o.__class__.__name__) return m(o) def build_List(self, o): return map(self.build, o.getChildren()) def build_Const(self, o): return o.value def build_Dict(self, o): d = {} i = iter(map(self.build, o.getChildren())) for el in i: d[el] = i.next() return d def build_Tuple(self, o): return tuple(self.build_List(o)) def build_Name(self, o): if o.name == 'None': return None if o.name == 'True': return True if o.name == 'False': return False # An undefined Name raise UnknownType('Undefined Name') def build_Add(self, o): real, imag = map(self.build_Const, o.getChildren()) try: real = float(real) except TypeError: raise UnknownType('Add') if not isinstance(imag, complex) or imag.real != 0.0: raise UnknownType('Add') return real+imag def build_Getattr(self, o): parent = self.build(o.expr) return getattr(parent, o.attrname) def build_UnarySub(self, o): return -self.build_Const(o.getChildren()[0]) def build_UnaryAdd(self, o): return self.build_Const(o.getChildren()[0]) _builder = Builder() def unrepr(s): if not s: return s return _builder.build(getObj(s)) class ConfigObjError(SyntaxError): """ This is the base class for all errors that ConfigObj raises. It is a subclass of SyntaxError. """ def __init__(self, message='', line_number=None, line=''): self.line = line self.line_number = line_number SyntaxError.__init__(self, message) class NestingError(ConfigObjError): """ This error indicates a level of nesting that doesn't match. """ class ParseError(ConfigObjError): """ This error indicates that a line is badly written. It is neither a valid ``key = value`` line, nor a valid section marker line. """ class ReloadError(IOError): """ A 'reload' operation failed. This exception is a subclass of ``IOError``. """ def __init__(self): IOError.__init__(self, 'reload failed, filename is not set.') class DuplicateError(ConfigObjError): """ The keyword or section specified already exists. """ class ConfigspecError(ConfigObjError): """ An error occured whilst parsing a configspec. """ class InterpolationError(ConfigObjError): """Base class for the two interpolation errors.""" class InterpolationLoopError(InterpolationError): """Maximum interpolation depth exceeded in string interpolation.""" def __init__(self, option): InterpolationError.__init__( self, 'interpolation loop detected in value "%s".' % option) class RepeatSectionError(ConfigObjError): """ This error indicates additional sections in a section with a ``__many__`` (repeated) section. """ class MissingInterpolationOption(InterpolationError): """A value specified for interpolation was missing.""" def __init__(self, option): msg = 'missing option "%s" in interpolation.' % option InterpolationError.__init__(self, msg) class UnreprError(ConfigObjError): """An error parsing in unrepr mode.""" class InterpolationEngine(object): """ A helper class to help perform string interpolation. This class is an abstract base class; its descendants perform the actual work. """ # compiled regexp to use in self.interpolate() _KEYCRE = re.compile(r"%\(([^)]*)\)s") _cookie = '%' def __init__(self, section): # the Section instance that "owns" this engine self.section = section def interpolate(self, key, value): # short-cut if not self._cookie in value: return value def recursive_interpolate(key, value, section, backtrail): """The function that does the actual work. ``value``: the string we're trying to interpolate. ``section``: the section in which that string was found ``backtrail``: a dict to keep track of where we've been, to detect and prevent infinite recursion loops This is similar to a depth-first-search algorithm. """ # Have we been here already? if (key, section.name) in backtrail: # Yes - infinite loop detected raise InterpolationLoopError(key) # Place a marker on our backtrail so we won't come back here again backtrail[(key, section.name)] = 1 # Now start the actual work match = self._KEYCRE.search(value) while match: # The actual parsing of the match is implementation-dependent, # so delegate to our helper function k, v, s = self._parse_match(match) if k is None: # That's the signal that no further interpolation is needed replacement = v else: # Further interpolation may be needed to obtain final value replacement = recursive_interpolate(k, v, s, backtrail) # Replace the matched string with its final value start, end = match.span() value = ''.join((value[:start], replacement, value[end:])) new_search_start = start + len(replacement) # Pick up the next interpolation key, if any, for next time # through the while loop match = self._KEYCRE.search(value, new_search_start) # Now safe to come back here again; remove marker from backtrail del backtrail[(key, section.name)] return value # Back in interpolate(), all we have to do is kick off the recursive # function with appropriate starting values value = recursive_interpolate(key, value, self.section, {}) return value def _fetch(self, key): """Helper function to fetch values from owning section. Returns a 2-tuple: the value, and the section where it was found. """ # switch off interpolation before we try and fetch anything ! save_interp = self.section.main.interpolation self.section.main.interpolation = False # Start at section that "owns" this InterpolationEngine current_section = self.section while True: # try the current section first val = current_section.get(key) if val is not None and not isinstance(val, Section): break # try "DEFAULT" next val = current_section.get('DEFAULT', {}).get(key) if val is not None and not isinstance(val, Section): break # move up to parent and try again # top-level's parent is itself if current_section.parent is current_section: # reached top level, time to give up break current_section = current_section.parent # restore interpolation to previous value before returning self.section.main.interpolation = save_interp if val is None: raise MissingInterpolationOption(key) return val, current_section def _parse_match(self, match): """Implementation-dependent helper function. Will be passed a match object corresponding to the interpolation key we just found (e.g., "%(foo)s" or "$foo"). Should look up that key in the appropriate config file section (using the ``_fetch()`` helper function) and return a 3-tuple: (key, value, section) ``key`` is the name of the key we're looking for ``value`` is the value found for that key ``section`` is a reference to the section where it was found ``key`` and ``section`` should be None if no further interpolation should be performed on the resulting value (e.g., if we interpolated "$$" and returned "$"). """ raise NotImplementedError() class ConfigParserInterpolation(InterpolationEngine): """Behaves like ConfigParser.""" _cookie = '%' _KEYCRE = re.compile(r"%\(([^)]*)\)s") def _parse_match(self, match): key = match.group(1) value, section = self._fetch(key) return key, value, section class TemplateInterpolation(InterpolationEngine): """Behaves like string.Template.""" _cookie = '$' _delimiter = '$' _KEYCRE = re.compile(r""" \$(?: (?P\$) | # Two $ signs (?P[_a-z][_a-z0-9]*) | # $name format {(?P[^}]*)} # ${name} format ) """, re.IGNORECASE | re.VERBOSE) def _parse_match(self, match): # Valid name (in or out of braces): fetch value from section key = match.group('named') or match.group('braced') if key is not None: value, section = self._fetch(key) return key, value, section # Escaped delimiter (e.g., $$): return single delimiter if match.group('escaped') is not None: # Return None for key and section to indicate it's time to stop return None, self._delimiter, None # Anything else: ignore completely, just return it unchanged return None, match.group(), None interpolation_engines = { 'configparser': ConfigParserInterpolation, 'template': TemplateInterpolation, } def __newobj__(cls, *args): # Hack for pickle return cls.__new__(cls, *args) class Section(dict): """ A dictionary-like object that represents a section in a config file. It does string interpolation if the 'interpolation' attribute of the 'main' object is set to True. Interpolation is tried first from this object, then from the 'DEFAULT' section of this object, next from the parent and its 'DEFAULT' section, and so on until the main object is reached. A Section will behave like an ordered dictionary - following the order of the ``scalars`` and ``sections`` attributes. You can use this to change the order of members. Iteration follows the order: scalars, then sections. """ def __setstate__(self, state): dict.update(self, state[0]) self.__dict__.update(state[1]) def __reduce__(self): state = (dict(self), self.__dict__) return (__newobj__, (self.__class__,), state) def __init__(self, parent, depth, main, indict=None, name=None): """ * parent is the section above * depth is the depth level of this section * main is the main ConfigObj * indict is a dictionary to initialise the section with """ if indict is None: indict = {} dict.__init__(self) # used for nesting level *and* interpolation self.parent = parent # used for the interpolation attribute self.main = main # level of nesting depth of this Section self.depth = depth # purely for information self.name = name # self._initialise() # we do this explicitly so that __setitem__ is used properly # (rather than just passing to ``dict.__init__``) for entry, value in indict.iteritems(): self[entry] = value def _initialise(self): # the sequence of scalar values in this Section self.scalars = [] # the sequence of sections in this Section self.sections = [] # for comments :-) self.comments = {} self.inline_comments = {} # the configspec self.configspec = None # for defaults self.defaults = [] self.default_values = {} self.extra_values = [] self._created = False def _interpolate(self, key, value): try: # do we already have an interpolation engine? engine = self._interpolation_engine except AttributeError: # not yet: first time running _interpolate(), so pick the engine name = self.main.interpolation if name == True: # note that "if name:" would be incorrect here # backwards-compatibility: interpolation=True means use default name = DEFAULT_INTERPOLATION name = name.lower() # so that "Template", "template", etc. all work class_ = interpolation_engines.get(name, None) if class_ is None: # invalid value for self.main.interpolation self.main.interpolation = False return value else: # save reference to engine so we don't have to do this again engine = self._interpolation_engine = class_(self) # let the engine do the actual work return engine.interpolate(key, value) def __getitem__(self, key): """Fetch the item and do string interpolation.""" val = dict.__getitem__(self, key) if self.main.interpolation: if isinstance(val, basestring): return self._interpolate(key, val) if isinstance(val, list): def _check(entry): if isinstance(entry, basestring): return self._interpolate(key, entry) return entry new = [_check(entry) for entry in val] if new != val: return new return val def __setitem__(self, key, value, unrepr=False): """ Correctly set a value. Making dictionary values Section instances. (We have to special case 'Section' instances - which are also dicts) Keys must be strings. Values need only be strings (or lists of strings) if ``main.stringify`` is set. ``unrepr`` must be set when setting a value to a dictionary, without creating a new sub-section. """ if not isinstance(key, basestring): raise ValueError('The key "%s" is not a string.' % key) # add the comment if key not in self.comments: self.comments[key] = [] self.inline_comments[key] = '' # remove the entry from defaults if key in self.defaults: self.defaults.remove(key) # if isinstance(value, Section): if key not in self: self.sections.append(key) dict.__setitem__(self, key, value) elif isinstance(value, dict) and not unrepr: # First create the new depth level, # then create the section if key not in self: self.sections.append(key) new_depth = self.depth + 1 dict.__setitem__( self, key, Section( self, new_depth, self.main, indict=value, name=key)) else: if key not in self: self.scalars.append(key) if not self.main.stringify: if isinstance(value, basestring): pass elif isinstance(value, (list, tuple)): for entry in value: if not isinstance(entry, basestring): raise TypeError('Value is not a string "%s".' % entry) else: raise TypeError('Value is not a string "%s".' % value) dict.__setitem__(self, key, value) def __delitem__(self, key): """Remove items from the sequence when deleting.""" dict. __delitem__(self, key) if key in self.scalars: self.scalars.remove(key) else: self.sections.remove(key) del self.comments[key] del self.inline_comments[key] def get(self, key, default=None): """A version of ``get`` that doesn't bypass string interpolation.""" try: return self[key] except KeyError: return default def update(self, indict): """ A version of update that uses our ``__setitem__``. """ for entry in indict: self[entry] = indict[entry] def pop(self, key, default=MISSING): """ 'D.pop(k[,d]) -> v, remove specified key and return the corresponding value. If key is not found, d is returned if given, otherwise KeyError is raised' """ try: val = self[key] except KeyError: if default is MISSING: raise val = default else: del self[key] return val def popitem(self): """Pops the first (key,val)""" sequence = (self.scalars + self.sections) if not sequence: raise KeyError(": 'popitem(): dictionary is empty'") key = sequence[0] val = self[key] del self[key] return key, val def clear(self): """ A version of clear that also affects scalars/sections Also clears comments and configspec. Leaves other attributes alone : depth/main/parent are not affected """ dict.clear(self) self.scalars = [] self.sections = [] self.comments = {} self.inline_comments = {} self.configspec = None self.defaults = [] self.extra_values = [] def setdefault(self, key, default=None): """A version of setdefault that sets sequence if appropriate.""" try: return self[key] except KeyError: self[key] = default return self[key] def items(self): """D.items() -> list of D's (key, value) pairs, as 2-tuples""" return zip((self.scalars + self.sections), self.values()) def keys(self): """D.keys() -> list of D's keys""" return (self.scalars + self.sections) def values(self): """D.values() -> list of D's values""" return [self[key] for key in (self.scalars + self.sections)] def iteritems(self): """D.iteritems() -> an iterator over the (key, value) items of D""" return iter(self.items()) def iterkeys(self): """D.iterkeys() -> an iterator over the keys of D""" return iter((self.scalars + self.sections)) __iter__ = iterkeys def itervalues(self): """D.itervalues() -> an iterator over the values of D""" return iter(self.values()) def __repr__(self): """x.__repr__() <==> repr(x)""" def _getval(key): try: return self[key] except MissingInterpolationOption: return dict.__getitem__(self, key) return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(_getval(key)))) for key in (self.scalars + self.sections)]) __str__ = __repr__ __str__.__doc__ = "x.__str__() <==> str(x)" # Extra methods - not in a normal dictionary def dict(self): """ Return a deepcopy of self as a dictionary. All members that are ``Section`` instances are recursively turned to ordinary dictionaries - by calling their ``dict`` method. >>> n = a.dict() >>> n == a 1 >>> n is a 0 """ newdict = {} for entry in self: this_entry = self[entry] if isinstance(this_entry, Section): this_entry = this_entry.dict() elif isinstance(this_entry, list): # create a copy rather than a reference this_entry = list(this_entry) elif isinstance(this_entry, tuple): # create a copy rather than a reference this_entry = tuple(this_entry) newdict[entry] = this_entry return newdict def merge(self, indict): """ A recursive update - useful for merging config files. >>> a = '''[section1] ... option1 = True ... [[subsection]] ... more_options = False ... # end of file'''.splitlines() >>> b = '''# File is user.ini ... [section1] ... option1 = False ... # end of file'''.splitlines() >>> c1 = ConfigObj(b) >>> c2 = ConfigObj(a) >>> c2.merge(c1) >>> c2 ConfigObj({'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}}) """ for key, val in indict.items(): if (key in self and isinstance(self[key], dict) and isinstance(val, dict)): self[key].merge(val) else: self[key] = val def rename(self, oldkey, newkey): """ Change a keyname to another, without changing position in sequence. Implemented so that transformations can be made on keys, as well as on values. (used by encode and decode) Also renames comments. """ if oldkey in self.scalars: the_list = self.scalars elif oldkey in self.sections: the_list = self.sections else: raise KeyError('Key "%s" not found.' % oldkey) pos = the_list.index(oldkey) # val = self[oldkey] dict.__delitem__(self, oldkey) dict.__setitem__(self, newkey, val) the_list.remove(oldkey) the_list.insert(pos, newkey) comm = self.comments[oldkey] inline_comment = self.inline_comments[oldkey] del self.comments[oldkey] del self.inline_comments[oldkey] self.comments[newkey] = comm self.inline_comments[newkey] = inline_comment def walk(self, function, raise_errors=True, call_on_sections=False, **keywargs): """ Walk every member and call a function on the keyword and value. Return a dictionary of the return values If the function raises an exception, raise the errror unless ``raise_errors=False``, in which case set the return value to ``False``. Any unrecognised keyword arguments you pass to walk, will be pased on to the function you pass in. Note: if ``call_on_sections`` is ``True`` then - on encountering a subsection, *first* the function is called for the *whole* subsection, and then recurses into it's members. This means your function must be able to handle strings, dictionaries and lists. This allows you to change the key of subsections as well as for ordinary members. The return value when called on the whole subsection has to be discarded. See the encode and decode methods for examples, including functions. .. admonition:: caution You can use ``walk`` to transform the names of members of a section but you mustn't add or delete members. >>> config = '''[XXXXsection] ... XXXXkey = XXXXvalue'''.splitlines() >>> cfg = ConfigObj(config) >>> cfg ConfigObj({'XXXXsection': {'XXXXkey': 'XXXXvalue'}}) >>> def transform(section, key): ... val = section[key] ... newkey = key.replace('XXXX', 'CLIENT1') ... section.rename(key, newkey) ... if isinstance(val, (tuple, list, dict)): ... pass ... else: ... val = val.replace('XXXX', 'CLIENT1') ... section[newkey] = val >>> cfg.walk(transform, call_on_sections=True) {'CLIENT1section': {'CLIENT1key': None}} >>> cfg ConfigObj({'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}}) """ out = {} # scalars first for i in range(len(self.scalars)): entry = self.scalars[i] try: val = function(self, entry, **keywargs) # bound again in case name has changed entry = self.scalars[i] out[entry] = val except Exception: if raise_errors: raise else: entry = self.scalars[i] out[entry] = False # then sections for i in range(len(self.sections)): entry = self.sections[i] if call_on_sections: try: function(self, entry, **keywargs) except Exception: if raise_errors: raise else: entry = self.sections[i] out[entry] = False # bound again in case name has changed entry = self.sections[i] # previous result is discarded out[entry] = self[entry].walk( function, raise_errors=raise_errors, call_on_sections=call_on_sections, **keywargs) return out def as_bool(self, key): """ Accepts a key as input. The corresponding value must be a string or the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to retain compatibility with Python 2.2. If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns ``True``. If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns ``False``. ``as_bool`` is not case sensitive. Any other input will raise a ``ValueError``. >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_bool('a') Traceback (most recent call last): ValueError: Value "fish" is neither True nor False >>> a['b'] = 'True' >>> a.as_bool('b') 1 >>> a['b'] = 'off' >>> a.as_bool('b') 0 """ val = self[key] if val == True: return True elif val == False: return False else: try: if not isinstance(val, basestring): # TODO: Why do we raise a KeyError here? raise KeyError() else: return self.main._bools[val.lower()] except KeyError: raise ValueError('Value "%s" is neither True nor False' % val) def as_int(self, key): """ A convenience method which coerces the specified value to an integer. If the value is an invalid literal for ``int``, a ``ValueError`` will be raised. >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_int('a') Traceback (most recent call last): ValueError: invalid literal for int() with base 10: 'fish' >>> a['b'] = '1' >>> a.as_int('b') 1 >>> a['b'] = '3.2' >>> a.as_int('b') Traceback (most recent call last): ValueError: invalid literal for int() with base 10: '3.2' """ return int(self[key]) def as_float(self, key): """ A convenience method which coerces the specified value to a float. If the value is an invalid literal for ``float``, a ``ValueError`` will be raised. >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_float('a') Traceback (most recent call last): ValueError: invalid literal for float(): fish >>> a['b'] = '1' >>> a.as_float('b') 1.0 >>> a['b'] = '3.2' >>> a.as_float('b') 3.2000000000000002 """ return float(self[key]) def as_list(self, key): """ A convenience method which fetches the specified value, guaranteeing that it is a list. >>> a = ConfigObj() >>> a['a'] = 1 >>> a.as_list('a') [1] >>> a['a'] = (1,) >>> a.as_list('a') [1] >>> a['a'] = [1] >>> a.as_list('a') [1] """ result = self[key] if isinstance(result, (tuple, list)): return list(result) return [result] def restore_default(self, key): """ Restore (and return) default value for the specified key. This method will only work for a ConfigObj that was created with a configspec and has been validated. If there is no default value for this key, ``KeyError`` is raised. """ default = self.default_values[key] dict.__setitem__(self, key, default) if key not in self.defaults: self.defaults.append(key) return default def restore_defaults(self): """ Recursively restore default values to all members that have them. This method will only work for a ConfigObj that was created with a configspec and has been validated. It doesn't delete or modify entries without default values. """ for key in self.default_values: self.restore_default(key) for section in self.sections: self[section].restore_defaults() class ConfigObj(Section): """An object to read, create, and write config files.""" _keyword = re.compile(r'''^ # line start (\s*) # indentation ( # keyword (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'"=].*?) # no quotes ) \s*=\s* # divider (.*) # value (including list values and comments) $ # line end ''', re.VERBOSE) _sectionmarker = re.compile(r'''^ (\s*) # 1: indentation ((?:\[\s*)+) # 2: section marker open ( # 3: section name open (?:"\s*\S.*?\s*")| # at least one non-space with double quotes (?:'\s*\S.*?\s*')| # at least one non-space with single quotes (?:[^'"\s].*?) # at least one non-space unquoted ) # section name close ((?:\s*\])+) # 4: section marker close \s*(\#.*)? # 5: optional comment $''', re.VERBOSE) # this regexp pulls list values out as a single string # or single values and comments # FIXME: this regex adds a '' to the end of comma terminated lists # workaround in ``_handle_value`` _valueexp = re.compile(r'''^ (?: (?: ( (?: (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#][^,\#]*?) # unquoted ) \s*,\s* # comma )* # match all list items ending in a comma (if any) ) ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#\s][^,]*?)| # unquoted (?:(? 1: msg = "Parsing failed with several errors.\nFirst error %s" % info error = ConfigObjError(msg) else: error = self._errors[0] # set the errors attribute; it's a list of tuples: # (error_type, message, line_number) error.errors = self._errors # set the config attribute error.config = self raise error # delete private attributes del self._errors if configspec is None: self.configspec = None else: self._handle_configspec(configspec) def _initialise(self, options=None): if options is None: options = OPTION_DEFAULTS # initialise a few variables self.filename = None self._errors = [] self.raise_errors = options['raise_errors'] self.interpolation = options['interpolation'] self.list_values = options['list_values'] self.create_empty = options['create_empty'] self.file_error = options['file_error'] self.stringify = options['stringify'] self.indent_type = options['indent_type'] self.encoding = options['encoding'] self.default_encoding = options['default_encoding'] self.BOM = False self.newlines = None self.write_empty_values = options['write_empty_values'] self.unrepr = options['unrepr'] self.initial_comment = [] self.final_comment = [] self.configspec = None if self._inspec: self.list_values = False # Clear section attributes as well Section._initialise(self) def __repr__(self): def _getval(key): try: return self[key] except MissingInterpolationOption: return dict.__getitem__(self, key) return ('ConfigObj({%s})' % ', '.join([('%s: %s' % (repr(key), repr(_getval(key)))) for key in (self.scalars + self.sections)])) def _handle_bom(self, infile): """ Handle any BOM, and decode if necessary. If an encoding is specified, that *must* be used - but the BOM should still be removed (and the BOM attribute set). (If the encoding is wrongly specified, then a BOM for an alternative encoding won't be discovered or removed.) If an encoding is not specified, UTF8 or UTF16 BOM will be detected and removed. The BOM attribute will be set. UTF16 will be decoded to unicode. NOTE: This method must not be called with an empty ``infile``. Specifying the *wrong* encoding is likely to cause a ``UnicodeDecodeError``. ``infile`` must always be returned as a list of lines, but may be passed in as a single string. """ if ((self.encoding is not None) and (self.encoding.lower() not in BOM_LIST)): # No need to check for a BOM # the encoding specified doesn't have one # just decode return self._decode(infile, self.encoding) if isinstance(infile, (list, tuple)): line = infile[0] else: line = infile if self.encoding is not None: # encoding explicitly supplied # And it could have an associated BOM # TODO: if encoding is just UTF16 - we ought to check for both # TODO: big endian and little endian versions. enc = BOM_LIST[self.encoding.lower()] if enc == 'utf_16': # For UTF16 we try big endian and little endian for BOM, (encoding, final_encoding) in BOMS.items(): if not final_encoding: # skip UTF8 continue if infile.startswith(BOM): ### BOM discovered ##self.BOM = True # Don't need to remove BOM return self._decode(infile, encoding) # If we get this far, will *probably* raise a DecodeError # As it doesn't appear to start with a BOM return self._decode(infile, self.encoding) # Must be UTF8 BOM = BOM_SET[enc] if not line.startswith(BOM): return self._decode(infile, self.encoding) newline = line[len(BOM):] # BOM removed if isinstance(infile, (list, tuple)): infile[0] = newline else: infile = newline self.BOM = True return self._decode(infile, self.encoding) # No encoding specified - so we need to check for UTF8/UTF16 for BOM, (encoding, final_encoding) in BOMS.items(): if not line.startswith(BOM): continue else: # BOM discovered self.encoding = final_encoding if not final_encoding: self.BOM = True # UTF8 # remove BOM newline = line[len(BOM):] if isinstance(infile, (list, tuple)): infile[0] = newline else: infile = newline # UTF8 - don't decode if isinstance(infile, basestring): return infile.splitlines(True) else: return infile # UTF16 - have to decode return self._decode(infile, encoding) # No BOM discovered and no encoding specified, just return if isinstance(infile, basestring): # infile read from a file will be a single string return infile.splitlines(True) return infile def _a_to_u(self, aString): """Decode ASCII strings to unicode if a self.encoding is specified.""" if self.encoding: return aString.decode('ascii') else: return aString def _decode(self, infile, encoding): """ Decode infile to unicode. Using the specified encoding. if is a string, it also needs converting to a list. """ if isinstance(infile, basestring): # can't be unicode # NOTE: Could raise a ``UnicodeDecodeError`` return infile.decode(encoding).splitlines(True) for i, line in enumerate(infile): if not isinstance(line, unicode): # NOTE: The isinstance test here handles mixed lists of unicode/string # NOTE: But the decode will break on any non-string values # NOTE: Or could raise a ``UnicodeDecodeError`` infile[i] = line.decode(encoding) return infile def _decode_element(self, line): """Decode element to unicode if necessary.""" if not self.encoding: return line if isinstance(line, str) and self.default_encoding: return line.decode(self.default_encoding) return line def _str(self, value): """ Used by ``stringify`` within validate, to turn non-string values into strings. """ if not isinstance(value, basestring): return str(value) else: return value def _parse(self, infile): """Actually parse the config file.""" temp_list_values = self.list_values if self.unrepr: self.list_values = False comment_list = [] done_start = False this_section = self maxline = len(infile) - 1 cur_index = -1 reset_comment = False while cur_index < maxline: if reset_comment: comment_list = [] cur_index += 1 line = infile[cur_index] sline = line.strip() # do we have anything on the line ? if not sline or sline.startswith('#'): reset_comment = False comment_list.append(line) continue if not done_start: # preserve initial comment self.initial_comment = comment_list comment_list = [] done_start = True reset_comment = True # first we check if it's a section marker mat = self._sectionmarker.match(line) if mat is not None: # is a section line (indent, sect_open, sect_name, sect_close, comment) = mat.groups() if indent and (self.indent_type is None): self.indent_type = indent cur_depth = sect_open.count('[') if cur_depth != sect_close.count(']'): self._handle_error("Cannot compute the section depth at line %s.", NestingError, infile, cur_index) continue if cur_depth < this_section.depth: # the new section is dropping back to a previous level try: parent = self._match_depth(this_section, cur_depth).parent except SyntaxError: self._handle_error("Cannot compute nesting level at line %s.", NestingError, infile, cur_index) continue elif cur_depth == this_section.depth: # the new section is a sibling of the current section parent = this_section.parent elif cur_depth == this_section.depth + 1: # the new section is a child the current section parent = this_section else: self._handle_error("Section too nested at line %s.", NestingError, infile, cur_index) sect_name = self._unquote(sect_name) if sect_name in parent: self._handle_error('Duplicate section name at line %s.', DuplicateError, infile, cur_index) continue # create the new section this_section = Section( parent, cur_depth, self, name=sect_name) parent[sect_name] = this_section parent.inline_comments[sect_name] = comment parent.comments[sect_name] = comment_list continue # # it's not a section marker, # so it should be a valid ``key = value`` line mat = self._keyword.match(line) if mat is None: # it neither matched as a keyword # or a section marker self._handle_error( 'Invalid line at line "%s".', ParseError, infile, cur_index) else: # is a keyword value # value will include any inline comment (indent, key, value) = mat.groups() if indent and (self.indent_type is None): self.indent_type = indent # check for a multiline value if value[:3] in ['"""', "'''"]: try: value, comment, cur_index = self._multiline( value, infile, cur_index, maxline) except SyntaxError: self._handle_error( 'Parse error in value at line %s.', ParseError, infile, cur_index) continue else: if self.unrepr: comment = '' try: value = unrepr(value) except Exception, e: if type(e) == UnknownType: msg = 'Unknown name or type in value at line %s.' else: msg = 'Parse error in value at line %s.' self._handle_error(msg, UnreprError, infile, cur_index) continue else: if self.unrepr: comment = '' try: value = unrepr(value) except Exception, e: if isinstance(e, UnknownType): msg = 'Unknown name or type in value at line %s.' else: msg = 'Parse error in value at line %s.' self._handle_error(msg, UnreprError, infile, cur_index) continue else: # extract comment and lists try: (value, comment) = self._handle_value(value) except SyntaxError: self._handle_error( 'Parse error in value at line %s.', ParseError, infile, cur_index) continue # key = self._unquote(key) if key in this_section: self._handle_error( 'Duplicate keyword name at line %s.', DuplicateError, infile, cur_index) continue # add the key. # we set unrepr because if we have got this far we will never # be creating a new section this_section.__setitem__(key, value, unrepr=True) this_section.inline_comments[key] = comment this_section.comments[key] = comment_list continue # if self.indent_type is None: # no indentation used, set the type accordingly self.indent_type = '' # preserve the final comment if not self and not self.initial_comment: self.initial_comment = comment_list elif not reset_comment: self.final_comment = comment_list self.list_values = temp_list_values def _match_depth(self, sect, depth): """ Given a section and a depth level, walk back through the sections parents to see if the depth level matches a previous section. Return a reference to the right section, or raise a SyntaxError. """ while depth < sect.depth: if sect is sect.parent: # we've reached the top level already raise SyntaxError() sect = sect.parent if sect.depth == depth: return sect # shouldn't get here raise SyntaxError() def _handle_error(self, text, ErrorClass, infile, cur_index): """ Handle an error according to the error settings. Either raise the error or store it. The error will have occured at ``cur_index`` """ line = infile[cur_index] cur_index += 1 message = text % cur_index error = ErrorClass(message, cur_index, line) if self.raise_errors: # raise the error - parsing stops here raise error # store the error # reraise when parsing has finished self._errors.append(error) def _unquote(self, value): """Return an unquoted version of a value""" if not value: # should only happen during parsing of lists raise SyntaxError if (value[0] == value[-1]) and (value[0] in ('"', "'")): value = value[1:-1] return value def _quote(self, value, multiline=True): """ Return a safely quoted version of a value. Raise a ConfigObjError if the value cannot be safely quoted. If multiline is ``True`` (default) then use triple quotes if necessary. * Don't quote values that don't need it. * Recursively quote members of a list and return a comma joined list. * Multiline is ``False`` for lists. * Obey list syntax for empty and single member lists. If ``list_values=False`` then the value is only quoted if it contains a ``\\n`` (is multiline) or '#'. If ``write_empty_values`` is set, and the value is an empty string, it won't be quoted. """ if multiline and self.write_empty_values and value == '': # Only if multiline is set, so that it is used for values not # keys, and not values that are part of a list return '' if multiline and isinstance(value, (list, tuple)): if not value: return ',' elif len(value) == 1: return self._quote(value[0], multiline=False) + ',' return ', '.join([self._quote(val, multiline=False) for val in value]) if not isinstance(value, basestring): if self.stringify: value = str(value) else: raise TypeError('Value "%s" is not a string.' % value) if not value: return '""' no_lists_no_quotes = not self.list_values and '\n' not in value and '#' not in value need_triple = multiline and ((("'" in value) and ('"' in value)) or ('\n' in value )) hash_triple_quote = multiline and not need_triple and ("'" in value) and ('"' in value) and ('#' in value) check_for_single = (no_lists_no_quotes or not need_triple) and not hash_triple_quote if check_for_single: if not self.list_values: # we don't quote if ``list_values=False`` quot = noquot # for normal values either single or double quotes will do elif '\n' in value: # will only happen if multiline is off - e.g. '\n' in key raise ConfigObjError('Value "%s" cannot be safely quoted.' % value) elif ((value[0] not in wspace_plus) and (value[-1] not in wspace_plus) and (',' not in value)): quot = noquot else: quot = self._get_single_quote(value) else: # if value has '\n' or "'" *and* '"', it will need triple quotes quot = self._get_triple_quote(value) if quot == noquot and '#' in value and self.list_values: quot = self._get_single_quote(value) return quot % value def _get_single_quote(self, value): if ("'" in value) and ('"' in value): raise ConfigObjError('Value "%s" cannot be safely quoted.' % value) elif '"' in value: quot = squot else: quot = dquot return quot def _get_triple_quote(self, value): if (value.find('"""') != -1) and (value.find("'''") != -1): raise ConfigObjError('Value "%s" cannot be safely quoted.' % value) if value.find('"""') == -1: quot = tdquot else: quot = tsquot return quot def _handle_value(self, value): """ Given a value string, unquote, remove comment, handle lists. (including empty and single member lists) """ if self._inspec: # Parsing a configspec so don't handle comments return (value, '') # do we look for lists in values ? if not self.list_values: mat = self._nolistvalue.match(value) if mat is None: raise SyntaxError() # NOTE: we don't unquote here return mat.groups() # mat = self._valueexp.match(value) if mat is None: # the value is badly constructed, probably badly quoted, # or an invalid list raise SyntaxError() (list_values, single, empty_list, comment) = mat.groups() if (list_values == '') and (single is None): # change this if you want to accept empty values raise SyntaxError() # NOTE: note there is no error handling from here if the regex # is wrong: then incorrect values will slip through if empty_list is not None: # the single comma - meaning an empty list return ([], comment) if single is not None: # handle empty values if list_values and not single: # FIXME: the '' is a workaround because our regex now matches # '' at the end of a list if it has a trailing comma single = None else: single = single or '""' single = self._unquote(single) if list_values == '': # not a list value return (single, comment) the_list = self._listvalueexp.findall(list_values) the_list = [self._unquote(val) for val in the_list] if single is not None: the_list += [single] return (the_list, comment) def _multiline(self, value, infile, cur_index, maxline): """Extract the value, where we are in a multiline situation.""" quot = value[:3] newvalue = value[3:] single_line = self._triple_quote[quot][0] multi_line = self._triple_quote[quot][1] mat = single_line.match(value) if mat is not None: retval = list(mat.groups()) retval.append(cur_index) return retval elif newvalue.find(quot) != -1: # somehow the triple quote is missing raise SyntaxError() # while cur_index < maxline: cur_index += 1 newvalue += '\n' line = infile[cur_index] if line.find(quot) == -1: newvalue += line else: # end of multiline, process it break else: # we've got to the end of the config, oops... raise SyntaxError() mat = multi_line.match(line) if mat is None: # a badly formed line raise SyntaxError() (value, comment) = mat.groups() return (newvalue + value, comment, cur_index) def _handle_configspec(self, configspec): """Parse the configspec.""" # FIXME: Should we check that the configspec was created with the # correct settings ? (i.e. ``list_values=False``) if not isinstance(configspec, ConfigObj): try: configspec = ConfigObj(configspec, raise_errors=True, file_error=True, _inspec=True) except ConfigObjError, e: # FIXME: Should these errors have a reference # to the already parsed ConfigObj ? raise ConfigspecError('Parsing configspec failed: %s' % e) except IOError, e: raise IOError('Reading configspec failed: %s' % e) self.configspec = configspec def _set_configspec(self, section, copy): """ Called by validate. Handles setting the configspec on subsections including sections to be validated by __many__ """ configspec = section.configspec many = configspec.get('__many__') if isinstance(many, dict): for entry in section.sections: if entry not in configspec: section[entry].configspec = many for entry in configspec.sections: if entry == '__many__': continue if entry not in section: section[entry] = {} section[entry]._created = True if copy: # copy comments section.comments[entry] = configspec.comments.get(entry, []) section.inline_comments[entry] = configspec.inline_comments.get(entry, '') # Could be a scalar when we expect a section if isinstance(section[entry], Section): section[entry].configspec = configspec[entry] def _write_line(self, indent_string, entry, this_entry, comment): """Write an individual line, for the write method""" # NOTE: the calls to self._quote here handles non-StringType values. if not self.unrepr: val = self._decode_element(self._quote(this_entry)) else: val = repr(this_entry) return '%s%s%s%s%s' % (indent_string, self._decode_element(self._quote(entry, multiline=False)), self._a_to_u(' = '), val, self._decode_element(comment)) def _write_marker(self, indent_string, depth, entry, comment): """Write a section marker line""" return '%s%s%s%s%s' % (indent_string, self._a_to_u('[' * depth), self._quote(self._decode_element(entry), multiline=False), self._a_to_u(']' * depth), self._decode_element(comment)) def _handle_comment(self, comment): """Deal with a comment.""" if not comment: return '' start = self.indent_type if not comment.startswith('#'): start += self._a_to_u(' # ') return (start + comment) # Public methods def write(self, outfile=None, section=None): """ Write the current ConfigObj as a file tekNico: FIXME: use StringIO instead of real files >>> filename = a.filename >>> a.filename = 'test.ini' >>> a.write() >>> a.filename = filename >>> a == ConfigObj('test.ini', raise_errors=True) 1 >>> import os >>> os.remove('test.ini') """ if self.indent_type is None: # this can be true if initialised from a dictionary self.indent_type = DEFAULT_INDENT_TYPE out = [] cs = self._a_to_u('#') csp = self._a_to_u('# ') if section is None: int_val = self.interpolation self.interpolation = False section = self for line in self.initial_comment: line = self._decode_element(line) stripped_line = line.strip() if stripped_line and not stripped_line.startswith(cs): line = csp + line out.append(line) indent_string = self.indent_type * section.depth for entry in (section.scalars + section.sections): if entry in section.defaults: # don't write out default values continue for comment_line in section.comments[entry]: comment_line = self._decode_element(comment_line.lstrip()) if comment_line and not comment_line.startswith(cs): comment_line = csp + comment_line out.append(indent_string + comment_line) this_entry = section[entry] comment = self._handle_comment(section.inline_comments[entry]) if isinstance(this_entry, dict): # a section out.append(self._write_marker( indent_string, this_entry.depth, entry, comment)) out.extend(self.write(section=this_entry)) else: out.append(self._write_line( indent_string, entry, this_entry, comment)) if section is self: for line in self.final_comment: line = self._decode_element(line) stripped_line = line.strip() if stripped_line and not stripped_line.startswith(cs): line = csp + line out.append(line) self.interpolation = int_val if section is not self: return out if (self.filename is None) and (outfile is None): # output a list of lines # might need to encode # NOTE: This will *screw* UTF16, each line will start with the BOM if self.encoding: out = [l.encode(self.encoding) for l in out] if (self.BOM and ((self.encoding is None) or (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))): # Add the UTF8 BOM if not out: out.append('') out[0] = BOM_UTF8 + out[0] return out # Turn the list to a string, joined with correct newlines newline = self.newlines or os.linesep if (getattr(outfile, 'mode', None) is not None and outfile.mode == 'w' and sys.platform == 'win32' and newline == '\r\n'): # Windows specific hack to avoid writing '\r\r\n' newline = '\n' output = self._a_to_u(newline).join(out) if self.encoding: output = output.encode(self.encoding) if self.BOM and ((self.encoding is None) or match_utf8(self.encoding)): # Add the UTF8 BOM output = BOM_UTF8 + output if not output.endswith(newline): output += newline if outfile is not None: outfile.write(output) else: h = open(self.filename, 'wb') h.write(output) h.close() def validate(self, validator, preserve_errors=False, copy=False, section=None): """ Test the ConfigObj against a configspec. It uses the ``validator`` object from *validate.py*. To run ``validate`` on the current ConfigObj, call: :: test = config.validate(validator) (Normally having previously passed in the configspec when the ConfigObj was created - you can dynamically assign a dictionary of checks to the ``configspec`` attribute of a section though). It returns ``True`` if everything passes, or a dictionary of pass/fails (True/False). If every member of a subsection passes, it will just have the value ``True``. (It also returns ``False`` if all members fail). In addition, it converts the values from strings to their native types if their checks pass (and ``stringify`` is set). If ``preserve_errors`` is ``True`` (``False`` is default) then instead of a marking a fail with a ``False``, it will preserve the actual exception object. This can contain info about the reason for failure. For example the ``VdtValueTooSmallError`` indicates that the value supplied was too small. If a value (or section) is missing it will still be marked as ``False``. You must have the validate module to use ``preserve_errors=True``. You can then use the ``flatten_errors`` function to turn your nested results dictionary into a flattened list of failures - useful for displaying meaningful error messages. """ if section is None: if self.configspec is None: raise ValueError('No configspec supplied.') if preserve_errors: # We do this once to remove a top level dependency on the validate module # Which makes importing configobj faster from validate import VdtMissingValue self._vdtMissingValue = VdtMissingValue section = self if copy: section.initial_comment = section.configspec.initial_comment section.final_comment = section.configspec.final_comment section.encoding = section.configspec.encoding section.BOM = section.configspec.BOM section.newlines = section.configspec.newlines section.indent_type = section.configspec.indent_type # # section.default_values.clear() #?? configspec = section.configspec self._set_configspec(section, copy) def validate_entry(entry, spec, val, missing, ret_true, ret_false): section.default_values.pop(entry, None) try: section.default_values[entry] = validator.get_default_value(configspec[entry]) except (KeyError, AttributeError, validator.baseErrorClass): # No default, bad default or validator has no 'get_default_value' # (e.g. SimpleVal) pass try: check = validator.check(spec, val, missing=missing ) except validator.baseErrorClass, e: if not preserve_errors or isinstance(e, self._vdtMissingValue): out[entry] = False else: # preserve the error out[entry] = e ret_false = False ret_true = False else: ret_false = False out[entry] = True if self.stringify or missing: # if we are doing type conversion # or the value is a supplied default if not self.stringify: if isinstance(check, (list, tuple)): # preserve lists check = [self._str(item) for item in check] elif missing and check is None: # convert the None from a default to a '' check = '' else: check = self._str(check) if (check != val) or missing: section[entry] = check if not copy and missing and entry not in section.defaults: section.defaults.append(entry) return ret_true, ret_false # out = {} ret_true = True ret_false = True unvalidated = [k for k in section.scalars if k not in configspec] incorrect_sections = [k for k in configspec.sections if k in section.scalars] incorrect_scalars = [k for k in configspec.scalars if k in section.sections] for entry in configspec.scalars: if entry in ('__many__', '___many___'): # reserved names continue if (not entry in section.scalars) or (entry in section.defaults): # missing entries # or entries from defaults missing = True val = None if copy and entry not in section.scalars: # copy comments section.comments[entry] = ( configspec.comments.get(entry, [])) section.inline_comments[entry] = ( configspec.inline_comments.get(entry, '')) # else: missing = False val = section[entry] ret_true, ret_false = validate_entry(entry, configspec[entry], val, missing, ret_true, ret_false) many = None if '__many__' in configspec.scalars: many = configspec['__many__'] elif '___many___' in configspec.scalars: many = configspec['___many___'] if many is not None: for entry in unvalidated: val = section[entry] ret_true, ret_false = validate_entry(entry, many, val, False, ret_true, ret_false) unvalidated = [] for entry in incorrect_scalars: ret_true = False if not preserve_errors: out[entry] = False else: ret_false = False msg = 'Value %r was provided as a section' % entry out[entry] = validator.baseErrorClass(msg) for entry in incorrect_sections: ret_true = False if not preserve_errors: out[entry] = False else: ret_false = False msg = 'Section %r was provided as a single value' % entry out[entry] = validator.baseErrorClass(msg) # Missing sections will have been created as empty ones when the # configspec was read. for entry in section.sections: # FIXME: this means DEFAULT is not copied in copy mode if section is self and entry == 'DEFAULT': continue if section[entry].configspec is None: unvalidated.append(entry) continue if copy: section.comments[entry] = configspec.comments.get(entry, []) section.inline_comments[entry] = configspec.inline_comments.get(entry, '') check = self.validate(validator, preserve_errors=preserve_errors, copy=copy, section=section[entry]) out[entry] = check if check == False: ret_true = False elif check == True: ret_false = False else: ret_true = False section.extra_values = unvalidated if preserve_errors and not section._created: # If the section wasn't created (i.e. it wasn't missing) # then we can't return False, we need to preserve errors ret_false = False # if ret_false and preserve_errors and out: # If we are preserving errors, but all # the failures are from missing sections / values # then we can return False. Otherwise there is a # real failure that we need to preserve. ret_false = not any(out.values()) if ret_true: return True elif ret_false: return False return out def reset(self): """Clear ConfigObj instance and restore to 'freshly created' state.""" self.clear() self._initialise() # FIXME: Should be done by '_initialise', but ConfigObj constructor (and reload) # requires an empty dictionary self.configspec = None # Just to be sure ;-) self._original_configspec = None def reload(self): """ Reload a ConfigObj from file. This method raises a ``ReloadError`` if the ConfigObj doesn't have a filename attribute pointing to a file. """ if not isinstance(self.filename, basestring): raise ReloadError() filename = self.filename current_options = {} for entry in OPTION_DEFAULTS: if entry == 'configspec': continue current_options[entry] = getattr(self, entry) configspec = self._original_configspec current_options['configspec'] = configspec self.clear() self._initialise(current_options) self._load(filename, configspec) class SimpleVal(object): """ A simple validator. Can be used to check that all members expected are present. To use it, provide a configspec with all your members in (the value given will be ignored). Pass an instance of ``SimpleVal`` to the ``validate`` method of your ``ConfigObj``. ``validate`` will return ``True`` if all members are present, or a dictionary with True/False meaning present/missing. (Whole missing sections will be replaced with ``False``) """ def __init__(self): self.baseErrorClass = ConfigObjError def check(self, check, member, missing=False): """A dummy check method, always returns the value unchanged.""" if missing: raise self.baseErrorClass() return member def flatten_errors(cfg, res, levels=None, results=None): """ An example function that will turn a nested dictionary of results (as returned by ``ConfigObj.validate``) into a flat list. ``cfg`` is the ConfigObj instance being checked, ``res`` is the results dictionary returned by ``validate``. (This is a recursive function, so you shouldn't use the ``levels`` or ``results`` arguments - they are used by the function.) Returns a list of keys that failed. Each member of the list is a tuple:: ([list of sections...], key, result) If ``validate`` was called with ``preserve_errors=False`` (the default) then ``result`` will always be ``False``. *list of sections* is a flattened list of sections that the key was found in. If the section was missing (or a section was expected and a scalar provided - or vice-versa) then key will be ``None``. If the value (or section) was missing then ``result`` will be ``False``. If ``validate`` was called with ``preserve_errors=True`` and a value was present, but failed the check, then ``result`` will be the exception object returned. You can use this as a string that describes the failure. For example *The value "3" is of the wrong type*. """ if levels is None: # first time called levels = [] results = [] if res == True: return results if res == False or isinstance(res, Exception): results.append((levels[:], None, res)) if levels: levels.pop() return results for (key, val) in res.items(): if val == True: continue if isinstance(cfg.get(key), dict): # Go down one level levels.append(key) flatten_errors(cfg[key], val, levels, results) continue results.append((levels[:], key, val)) # # Go up one level if levels: levels.pop() # return results def get_extra_values(conf, _prepend=()): """ Find all the values and sections not in the configspec from a validated ConfigObj. ``get_extra_values`` returns a list of tuples where each tuple represents either an extra section, or an extra value. The tuples contain two values, a tuple representing the section the value is in and the name of the extra values. For extra values in the top level section the first member will be an empty tuple. For values in the 'foo' section the first member will be ``('foo',)``. For members in the 'bar' subsection of the 'foo' section the first member will be ``('foo', 'bar')``. NOTE: If you call ``get_extra_values`` on a ConfigObj instance that hasn't been validated it will return an empty list. """ out = [] out.extend([(_prepend, name) for name in conf.extra_values]) for name in conf.sections: if name not in conf.extra_values: out.extend(get_extra_values(conf[name], _prepend + (name,))) return out """*A programming language is a medium of expression.* - Paul Graham""" SABnzbd-2.3.2/sabnzbd/utils/diskspeed.py0000644000000000000000000000443613217005257016250 0ustar 00000000000000#!/usr/bin/env python import time import os import sys import logging _DUMP_DATA = '*' * 10000 def writetofile(filename, mysizeMB): # writes string to specified file repeat delay, until mysizeMB is reached. writeloops = int(1024 * 1024 * mysizeMB / len(_DUMP_DATA)) try: f = open(filename, 'w') except: logging.debug('Cannot create file %s', filename) logging.debug("Traceback: ", exc_info=True) return False try: for x in xrange(writeloops): f.write(_DUMP_DATA) except: logging.debug('Cannot write to file %s', filename) logging.debug("Traceback: ", exc_info=True) return False f.close() return True def diskspeedmeasure(dirname): # returns writing speed to dirname in MB/s # method: keep writing a file, until 0.5 seconds is passed. Then divide bytes written by time passed filesize = 10 # MB maxtime = 0.5 # sec filename = os.path.join(dirname, 'outputTESTING.txt') if os.name == 'nt': # On Windows, this crazy action is needed to # avoid a "permission denied" error try: os.popen('echo Hi >%s' % filename) except: pass start = time.time() loopcounter = 0 while True: if not writetofile(filename, filesize): return 0 loopcounter += 1 diff = time.time() - start if diff > maxtime: break try: os.remove(filename) except: pass return (loopcounter * filesize) / diff if __name__ == "__main__": print "Let's go" if len(sys.argv) >= 2: dirname = sys.argv[1] if not os.path.isdir(dirname): print "Specified argument is not a directory. Bailing out" sys.exit(1) else: # no argument, so use current working directory dirname = os.getcwd() print "Using current working directory" try: speed = diskspeedmeasure(dirname) print "Disk writing speed: %.2f Mbytes per second" % speed except IOError, e: # print "IOError:", e if e.errno == 13: print "Could not create test file. Check that you have write rights to directory", dirname except: print "Something else went wrong" raise print "Done" SABnzbd-2.3.2/sabnzbd/utils/feedparser.py0000644000000000000000000050706013217005257016416 0ustar 00000000000000"""Universal feed parser Handles RSS 0.9x, RSS 1.0, RSS 2.0, CDF, Atom 0.3, and Atom 1.0 feeds Visit https://code.google.com/p/feedparser/ for the latest version Visit http://packages.python.org/feedparser/ for the latest documentation Required: Python 2.4 or later Recommended: iconv_codec """ __version__ = "5.1.3" __license__ = """ Copyright (c) 2010-2012 Kurt McKee Copyright (c) 2002-2008 Mark Pilgrim All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.""" __author__ = "Mark Pilgrim " __contributors__ = ["Jason Diamond ", "John Beimler ", "Fazal Majid ", "Aaron Swartz ", "Kevin Marks ", "Sam Ruby ", "Ade Oshineye ", "Martin Pool ", "Kurt McKee ", "Bernd Schlapsi ",] # HTTP "User-Agent" header to send to servers when downloading feeds. # If you are embedding feedparser in a larger application, you should # change this to your application name and URL. USER_AGENT = "UniversalFeedParser/%s +https://code.google.com/p/feedparser/" % __version__ # HTTP "Accept" header to send to servers when downloading feeds. If you don't # want to send an Accept header, set this to None. ACCEPT_HEADER = "application/atom+xml,application/rdf+xml,application/rss+xml,application/x-netcdf,application/xml;q=0.9,text/xml;q=0.2,*/*;q=0.1" # List of preferred XML parsers, by SAX driver name. These will be tried first, # but if they're not installed, Python will keep searching through its own list # of pre-installed parsers until it finds one that supports everything we need. PREFERRED_XML_PARSERS = ["drv_libxml2"] # If you want feedparser to automatically run HTML markup through HTML Tidy, set # this to 1. Requires mxTidy # or utidylib . TIDY_MARKUP = 0 # List of Python interfaces for HTML Tidy, in order of preference. Only useful # if TIDY_MARKUP = 1 PREFERRED_TIDY_INTERFACES = ["uTidy", "mxTidy"] # If you want feedparser to automatically resolve all relative URIs, set this # to 1. RESOLVE_RELATIVE_URIS = 1 # If you want feedparser to automatically sanitize all potentially unsafe # HTML content, set this to 1. SANITIZE_HTML = 0 # If you want feedparser to automatically parse microformat content embedded # in entry contents, set this to 1 PARSE_MICROFORMATS = 0 # ---------- Python 3 modules (make it work if possible) ---------- try: import rfc822 except ImportError: from email import _parseaddr as rfc822 try: # Python 3.1 introduces bytes.maketrans and simultaneously # deprecates string.maketrans; use bytes.maketrans if possible _maketrans = bytes.maketrans except (NameError, AttributeError): import string _maketrans = string.maketrans # base64 support for Atom feeds that contain embedded binary data try: import base64, binascii except ImportError: base64 = binascii = None else: # Python 3.1 deprecates decodestring in favor of decodebytes _base64decode = getattr(base64, 'decodebytes', base64.decodestring) # _s2bytes: convert a UTF-8 str to bytes if the interpreter is Python 3 # _l2bytes: convert a list of ints to bytes if the interpreter is Python 3 try: if bytes is str: # In Python 2.5 and below, bytes doesn't exist (NameError) # In Python 2.6 and above, bytes and str are the same type raise NameError except NameError: # Python 2 def _s2bytes(s): return s def _l2bytes(l): return ''.join(map(chr, l)) else: # Python 3 def _s2bytes(s): return bytes(s, 'utf8') def _l2bytes(l): return bytes(l) # If you want feedparser to allow all URL schemes, set this to () # List culled from Python's urlparse documentation at: # http://docs.python.org/library/urlparse.html # as well as from "URI scheme" at Wikipedia: # https://secure.wikimedia.org/wikipedia/en/wiki/URI_scheme # Many more will likely need to be added! ACCEPTABLE_URI_SCHEMES = ( 'file', 'ftp', 'gopher', 'h323', 'hdl', 'http', 'https', 'imap', 'magnet', 'mailto', 'mms', 'news', 'nntp', 'prospero', 'rsync', 'rtsp', 'rtspu', 'sftp', 'shttp', 'sip', 'sips', 'snews', 'svn', 'svn+ssh', 'telnet', 'wais', # Additional common-but-unofficial schemes 'aim', 'callto', 'cvs', 'facetime', 'feed', 'git', 'gtalk', 'irc', 'ircs', 'irc6', 'itms', 'mms', 'msnim', 'skype', 'ssh', 'smb', 'svn', 'ymsg', ) #ACCEPTABLE_URI_SCHEMES = () # ---------- required modules (should come with any Python distribution) ---------- import cgi import codecs import copy import datetime import re import struct import time import types import urllib import urllib2 import urlparse import warnings from htmlentitydefs import name2codepoint, codepoint2name, entitydefs try: from io import BytesIO as _StringIO except ImportError: try: from cStringIO import StringIO as _StringIO except ImportError: from StringIO import StringIO as _StringIO # ---------- optional modules (feedparser will work without these, but with reduced functionality) ---------- # gzip is included with most Python distributions, but may not be available if you compiled your own try: import gzip except ImportError: gzip = None try: import zlib except ImportError: zlib = None # If a real XML parser is available, feedparser will attempt to use it. feedparser has # been tested with the built-in SAX parser and libxml2. On platforms where the # Python distribution does not come with an XML parser (such as Mac OS X 10.2 and some # versions of FreeBSD), feedparser will quietly fall back on regex-based parsing. try: import xml.sax from xml.sax.saxutils import escape as _xmlescape except ImportError: _XML_AVAILABLE = 0 def _xmlescape(data,entities={}): data = data.replace('&', '&') data = data.replace('>', '>') data = data.replace('<', '<') for char, entity in entities: data = data.replace(char, entity) return data else: try: xml.sax.make_parser(PREFERRED_XML_PARSERS) # test for valid parsers except xml.sax.SAXReaderNotAvailable: _XML_AVAILABLE = 0 else: _XML_AVAILABLE = 1 # sgmllib is not available by default in Python 3; if the end user doesn't have # it available then we'll lose illformed XML parsing, content santizing, and # microformat support (at least while feedparser depends on BeautifulSoup). try: import sgmllib except ImportError: # This is probably Python 3, which doesn't include sgmllib anymore _SGML_AVAILABLE = 0 # Mock sgmllib enough to allow subclassing later on class sgmllib(object): class SGMLParser(object): def goahead(self, i): pass def parse_starttag(self, i): pass else: _SGML_AVAILABLE = 1 # sgmllib defines a number of module-level regular expressions that are # insufficient for the XML parsing feedparser needs. Rather than modify # the variables directly in sgmllib, they're defined here using the same # names, and the compiled code objects of several sgmllib.SGMLParser # methods are copied into _BaseHTMLProcessor so that they execute in # feedparser's scope instead of sgmllib's scope. charref = re.compile('&#(\d+|[xX][0-9a-fA-F]+);') tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*') attrfind = re.compile( r'\s*([a-zA-Z_][-:.a-zA-Z_0-9]*)[$]?(\s*=\s*' r'(\'[^\']*\'|"[^"]*"|[][\-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~\'"@]*))?' ) # Unfortunately, these must be copied over to prevent NameError exceptions entityref = sgmllib.entityref incomplete = sgmllib.incomplete interesting = sgmllib.interesting shorttag = sgmllib.shorttag shorttagopen = sgmllib.shorttagopen starttagopen = sgmllib.starttagopen class _EndBracketRegEx: def __init__(self): # Overriding the built-in sgmllib.endbracket regex allows the # parser to find angle brackets embedded in element attributes. self.endbracket = re.compile('''([^'"<>]|"[^"]*"(?=>|/|\s|\w+=)|'[^']*'(?=>|/|\s|\w+=))*(?=[<>])|.*?(?=[<>])''') def search(self, target, index=0): match = self.endbracket.match(target, index) if match is not None: # Returning a new object in the calling thread's context # resolves a thread-safety. return EndBracketMatch(match) return None class EndBracketMatch: def __init__(self, match): self.match = match def start(self, n): return self.match.end(n) endbracket = _EndBracketRegEx() # iconv_codec provides support for more character encodings. # It's available from http://cjkpython.i18n.org/ try: import iconv_codec except ImportError: pass # chardet library auto-detects character encodings # Download from http://chardet.feedparser.org/ try: import chardet except ImportError: chardet = None # BeautifulSoup is used to extract microformat content from HTML # feedparser is tested using BeautifulSoup 3.2.0 # http://www.crummy.com/software/BeautifulSoup/ try: import BeautifulSoup except ImportError: BeautifulSoup = None PARSE_MICROFORMATS = False # ---------- don't touch these ---------- class ThingsNobodyCaresAboutButMe(Exception): pass class CharacterEncodingOverride(ThingsNobodyCaresAboutButMe): pass class CharacterEncodingUnknown(ThingsNobodyCaresAboutButMe): pass class NonXMLContentType(ThingsNobodyCaresAboutButMe): pass class UndeclaredNamespace(Exception): pass SUPPORTED_VERSIONS = {'': u'unknown', 'rss090': u'RSS 0.90', 'rss091n': u'RSS 0.91 (Netscape)', 'rss091u': u'RSS 0.91 (Userland)', 'rss092': u'RSS 0.92', 'rss093': u'RSS 0.93', 'rss094': u'RSS 0.94', 'rss20': u'RSS 2.0', 'rss10': u'RSS 1.0', 'rss': u'RSS (unknown version)', 'atom01': u'Atom 0.1', 'atom02': u'Atom 0.2', 'atom03': u'Atom 0.3', 'atom10': u'Atom 1.0', 'atom': u'Atom (unknown version)', 'cdf': u'CDF', } class FeedParserDict(dict): keymap = {'channel': 'feed', 'items': 'entries', 'guid': 'id', 'date': 'updated', 'date_parsed': 'updated_parsed', 'description': ['summary', 'subtitle'], 'description_detail': ['summary_detail', 'subtitle_detail'], 'url': ['href'], 'modified': 'updated', 'modified_parsed': 'updated_parsed', 'issued': 'published', 'issued_parsed': 'published_parsed', 'copyright': 'rights', 'copyright_detail': 'rights_detail', 'tagline': 'subtitle', 'tagline_detail': 'subtitle_detail'} def __getitem__(self, key): if key == 'category': try: return dict.__getitem__(self, 'tags')[0]['term'] except IndexError: raise KeyError, "object doesn't have key 'category'" elif key == 'enclosures': norel = lambda link: FeedParserDict([(name,value) for (name,value) in link.items() if name!='rel']) return [norel(link) for link in dict.__getitem__(self, 'links') if link['rel']==u'enclosure'] elif key == 'license': for link in dict.__getitem__(self, 'links'): if link['rel']==u'license' and 'href' in link: return link['href'] elif key == 'updated': # Temporarily help developers out by keeping the old # broken behavior that was reported in issue 310. # This fix was proposed in issue 328. if not dict.__contains__(self, 'updated') and \ dict.__contains__(self, 'published'): warnings.warn("To avoid breaking existing software while " "fixing issue 310, a temporary mapping has been created " "from `updated` to `published` if `updated` doesn't " "exist. This fallback will be removed in a future version " "of feedparser.", DeprecationWarning) return dict.__getitem__(self, 'published') return dict.__getitem__(self, 'updated') elif key == 'updated_parsed': if not dict.__contains__(self, 'updated_parsed') and \ dict.__contains__(self, 'published_parsed'): warnings.warn("To avoid breaking existing software while " "fixing issue 310, a temporary mapping has been created " "from `updated_parsed` to `published_parsed` if " "`updated_parsed` doesn't exist. This fallback will be " "removed in a future version of feedparser.", DeprecationWarning) return dict.__getitem__(self, 'published_parsed') return dict.__getitem__(self, 'updated_parsed') else: realkey = self.keymap.get(key, key) if isinstance(realkey, list): for k in realkey: if dict.__contains__(self, k): return dict.__getitem__(self, k) elif dict.__contains__(self, realkey): return dict.__getitem__(self, realkey) return dict.__getitem__(self, key) def __contains__(self, key): if key in ('updated', 'updated_parsed'): # Temporarily help developers out by keeping the old # broken behavior that was reported in issue 310. # This fix was proposed in issue 328. return dict.__contains__(self, key) try: self.__getitem__(key) except KeyError: return False else: return True has_key = __contains__ def get(self, key, default=None): try: return self.__getitem__(key) except KeyError: return default def __setitem__(self, key, value): key = self.keymap.get(key, key) if isinstance(key, list): key = key[0] return dict.__setitem__(self, key, value) def setdefault(self, key, value): if key not in self: self[key] = value return value return self[key] def __getattr__(self, key): # __getattribute__() is called first; this will be called # only if an attribute was not already found try: return self.__getitem__(key) except KeyError: raise AttributeError, "object has no attribute '%s'" % key def __hash__(self): return id(self) _cp1252 = { 128: unichr(8364), # euro sign 130: unichr(8218), # single low-9 quotation mark 131: unichr( 402), # latin small letter f with hook 132: unichr(8222), # double low-9 quotation mark 133: unichr(8230), # horizontal ellipsis 134: unichr(8224), # dagger 135: unichr(8225), # double dagger 136: unichr( 710), # modifier letter circumflex accent 137: unichr(8240), # per mille sign 138: unichr( 352), # latin capital letter s with caron 139: unichr(8249), # single left-pointing angle quotation mark 140: unichr( 338), # latin capital ligature oe 142: unichr( 381), # latin capital letter z with caron 145: unichr(8216), # left single quotation mark 146: unichr(8217), # right single quotation mark 147: unichr(8220), # left double quotation mark 148: unichr(8221), # right double quotation mark 149: unichr(8226), # bullet 150: unichr(8211), # en dash 151: unichr(8212), # em dash 152: unichr( 732), # small tilde 153: unichr(8482), # trade mark sign 154: unichr( 353), # latin small letter s with caron 155: unichr(8250), # single right-pointing angle quotation mark 156: unichr( 339), # latin small ligature oe 158: unichr( 382), # latin small letter z with caron 159: unichr( 376), # latin capital letter y with diaeresis } _urifixer = re.compile('^([A-Za-z][A-Za-z0-9+-.]*://)(/*)(.*?)') def _urljoin(base, uri): uri = _urifixer.sub(r'\1\3', uri) #try: if not isinstance(uri, unicode): uri = uri.decode('utf-8', 'ignore') uri = urlparse.urljoin(base, uri) if not isinstance(uri, unicode): return uri.decode('utf-8', 'ignore') return uri #except: # uri = urlparse.urlunparse([urllib.quote(part) for part in urlparse.urlparse(uri)]) # return urlparse.urljoin(base, uri) class _FeedParserMixin: namespaces = { '': '', 'http://backend.userland.com/rss': '', 'http://blogs.law.harvard.edu/tech/rss': '', 'http://purl.org/rss/1.0/': '', 'http://my.netscape.com/rdf/simple/0.9/': '', 'http://example.com/newformat#': '', 'http://example.com/necho': '', 'http://purl.org/echo/': '', 'uri/of/echo/namespace#': '', 'http://purl.org/pie/': '', 'http://purl.org/atom/ns#': '', 'http://www.w3.org/2005/Atom': '', 'http://purl.org/rss/1.0/modules/rss091#': '', 'http://webns.net/mvcb/': 'admin', 'http://purl.org/rss/1.0/modules/aggregation/': 'ag', 'http://purl.org/rss/1.0/modules/annotate/': 'annotate', 'http://media.tangent.org/rss/1.0/': 'audio', 'http://backend.userland.com/blogChannelModule': 'blogChannel', 'http://web.resource.org/cc/': 'cc', 'http://backend.userland.com/creativeCommonsRssModule': 'creativeCommons', 'http://purl.org/rss/1.0/modules/company': 'co', 'http://purl.org/rss/1.0/modules/content/': 'content', 'http://my.theinfo.org/changed/1.0/rss/': 'cp', 'http://purl.org/dc/elements/1.1/': 'dc', 'http://purl.org/dc/terms/': 'dcterms', 'http://purl.org/rss/1.0/modules/email/': 'email', 'http://purl.org/rss/1.0/modules/event/': 'ev', 'http://rssnamespace.org/feedburner/ext/1.0': 'feedburner', 'http://freshmeat.net/rss/fm/': 'fm', 'http://xmlns.com/foaf/0.1/': 'foaf', 'http://www.w3.org/2003/01/geo/wgs84_pos#': 'geo', 'http://postneo.com/icbm/': 'icbm', 'http://purl.org/rss/1.0/modules/image/': 'image', 'http://www.itunes.com/DTDs/PodCast-1.0.dtd': 'itunes', 'http://example.com/DTDs/PodCast-1.0.dtd': 'itunes', 'http://purl.org/rss/1.0/modules/link/': 'l', 'http://search.yahoo.com/mrss': 'media', # Version 1.1.2 of the Media RSS spec added the trailing slash on the namespace 'http://search.yahoo.com/mrss/': 'media', 'http://madskills.com/public/xml/rss/module/pingback/': 'pingback', 'http://prismstandard.org/namespaces/1.2/basic/': 'prism', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#': 'rdf', 'http://www.w3.org/2000/01/rdf-schema#': 'rdfs', 'http://purl.org/rss/1.0/modules/reference/': 'ref', 'http://purl.org/rss/1.0/modules/richequiv/': 'reqv', 'http://purl.org/rss/1.0/modules/search/': 'search', 'http://purl.org/rss/1.0/modules/slash/': 'slash', 'http://schemas.xmlsoap.org/soap/envelope/': 'soap', 'http://purl.org/rss/1.0/modules/servicestatus/': 'ss', 'http://hacks.benhammersley.com/rss/streaming/': 'str', 'http://purl.org/rss/1.0/modules/subscription/': 'sub', 'http://purl.org/rss/1.0/modules/syndication/': 'sy', 'http://schemas.pocketsoap.com/rss/myDescModule/': 'szf', 'http://purl.org/rss/1.0/modules/taxonomy/': 'taxo', 'http://purl.org/rss/1.0/modules/threading/': 'thr', 'http://purl.org/rss/1.0/modules/textinput/': 'ti', 'http://madskills.com/public/xml/rss/module/trackback/': 'trackback', 'http://wellformedweb.org/commentAPI/': 'wfw', 'http://purl.org/rss/1.0/modules/wiki/': 'wiki', 'http://www.w3.org/1999/xhtml': 'xhtml', 'http://www.w3.org/1999/xlink': 'xlink', 'http://www.w3.org/XML/1998/namespace': 'xml', 'http://www.newznab.com/DTD/2010/feeds/attributes/': 'nZEDb', 'http://www.newznab.com/DTD/2010/feeds/attributes/': 'newznab', 'http://www.newznab.com/DTD/2010/feeds/attributes/': 'nntmux', } _matchnamespaces = {} can_be_relative_uri = set(['link', 'id', 'wfw_comment', 'wfw_commentrss', 'docs', 'url', 'href', 'comments', 'icon', 'logo']) can_contain_relative_uris = set(['content', 'title', 'summary', 'info', 'tagline', 'subtitle', 'copyright', 'rights', 'description']) can_contain_dangerous_markup = set(['content', 'title', 'summary', 'info', 'tagline', 'subtitle', 'copyright', 'rights', 'description']) html_types = [u'text/html', u'application/xhtml+xml'] def __init__(self, baseuri=None, baselang=None, encoding=u'utf-8'): if not self._matchnamespaces: for k, v in self.namespaces.items(): self._matchnamespaces[k.lower()] = v self.feeddata = FeedParserDict() # feed-level data self.encoding = encoding # character encoding self.entries = [] # list of entry-level data self.version = u'' # feed type/version, see SUPPORTED_VERSIONS self.namespacesInUse = {} # dictionary of namespaces defined by the feed # the following are used internally to track state; # this is really out of control and should be refactored self.infeed = 0 self.inentry = 0 self.incontent = 0 self.intextinput = 0 self.inimage = 0 self.inauthor = 0 self.incontributor = 0 self.inpublisher = 0 self.insource = 0 self.sourcedata = FeedParserDict() self.contentparams = FeedParserDict() self._summaryKey = None self.namespacemap = {} self.elementstack = [] self.basestack = [] self.langstack = [] self.baseuri = baseuri or u'' self.lang = baselang or None self.svgOK = 0 self.title_depth = -1 self.depth = 0 if baselang: self.feeddata['language'] = baselang.replace('_','-') # A map of the following form: # { # object_that_value_is_set_on: { # property_name: depth_of_node_property_was_extracted_from, # other_property: depth_of_node_property_was_extracted_from, # }, # } self.property_depth_map = {} def _normalize_attributes(self, kv): k = kv[0].lower() v = k in ('rel', 'type') and kv[1].lower() or kv[1] # the sgml parser doesn't handle entities in attributes, nor # does it pass the attribute values through as unicode, while # strict xml parsers do -- account for this difference if isinstance(self, _LooseFeedParser): v = v.replace('&', '&') if not isinstance(v, unicode): v = v.decode('utf-8') return (k, v) def unknown_starttag(self, tag, attrs): # increment depth counter self.depth += 1 # normalize attrs attrs = map(self._normalize_attributes, attrs) # track xml:base and xml:lang attrsD = dict(attrs) baseuri = attrsD.get('xml:base', attrsD.get('base')) or self.baseuri if not isinstance(baseuri, unicode): baseuri = baseuri.decode(self.encoding, 'ignore') # ensure that self.baseuri is always an absolute URI that # uses a whitelisted URI scheme (e.g. not `javscript:`) if self.baseuri: self.baseuri = _makeSafeAbsoluteURI(self.baseuri, baseuri) or self.baseuri else: self.baseuri = _urljoin(self.baseuri, baseuri) lang = attrsD.get('xml:lang', attrsD.get('lang')) if lang == '': # xml:lang could be explicitly set to '', we need to capture that lang = None elif lang is None: # if no xml:lang is specified, use parent lang lang = self.lang if lang: if tag in ('feed', 'rss', 'rdf:RDF'): self.feeddata['language'] = lang.replace('_','-') self.lang = lang self.basestack.append(self.baseuri) self.langstack.append(lang) # track namespaces for prefix, uri in attrs: if prefix.startswith('xmlns:'): self.trackNamespace(prefix[6:], uri) elif prefix == 'xmlns': self.trackNamespace(None, uri) # track inline content if self.incontent and not self.contentparams.get('type', u'xml').endswith(u'xml'): if tag in ('xhtml:div', 'div'): return # typepad does this 10/2007 # element declared itself as escaped markup, but it isn't really self.contentparams['type'] = u'application/xhtml+xml' if self.incontent and self.contentparams.get('type') == u'application/xhtml+xml': if tag.find(':') <> -1: prefix, tag = tag.split(':', 1) namespace = self.namespacesInUse.get(prefix, '') if tag=='math' and namespace=='http://www.w3.org/1998/Math/MathML': attrs.append(('xmlns',namespace)) if tag=='svg' and namespace=='http://www.w3.org/2000/svg': attrs.append(('xmlns',namespace)) if tag == 'svg': self.svgOK += 1 return self.handle_data('<%s%s>' % (tag, self.strattrs(attrs)), escape=0) # match namespaces if tag.find(':') <> -1: prefix, suffix = tag.split(':', 1) else: prefix, suffix = '', tag prefix = self.namespacemap.get(prefix, prefix) if prefix: prefix = prefix + '_' # special hack for better tracking of empty textinput/image elements in illformed feeds if (not prefix) and tag not in ('title', 'link', 'description', 'name'): self.intextinput = 0 if (not prefix) and tag not in ('title', 'link', 'description', 'url', 'href', 'width', 'height'): self.inimage = 0 # call special handler (if defined) or default handler methodname = '_start_' + prefix + suffix try: method = getattr(self, methodname) return method(attrsD) except AttributeError: # Since there's no handler or something has gone wrong we explicitly add the element and its attributes unknown_tag = prefix + suffix if len(attrsD) == 0: # No attributes so merge it into the encosing dictionary return self.push(unknown_tag, 1) else: # Has attributes so create it in its own dictionary context = self._getContext() context[unknown_tag] = attrsD def unknown_endtag(self, tag): # match namespaces if tag.find(':') <> -1: prefix, suffix = tag.split(':', 1) else: prefix, suffix = '', tag prefix = self.namespacemap.get(prefix, prefix) if prefix: prefix = prefix + '_' if suffix == 'svg' and self.svgOK: self.svgOK -= 1 # call special handler (if defined) or default handler methodname = '_end_' + prefix + suffix try: if self.svgOK: raise AttributeError() method = getattr(self, methodname) method() except AttributeError: self.pop(prefix + suffix) # track inline content if self.incontent and not self.contentparams.get('type', u'xml').endswith(u'xml'): # element declared itself as escaped markup, but it isn't really if tag in ('xhtml:div', 'div'): return # typepad does this 10/2007 self.contentparams['type'] = u'application/xhtml+xml' if self.incontent and self.contentparams.get('type') == u'application/xhtml+xml': tag = tag.split(':')[-1] self.handle_data('' % tag, escape=0) # track xml:base and xml:lang going out of scope if self.basestack: self.basestack.pop() if self.basestack and self.basestack[-1]: self.baseuri = self.basestack[-1] if self.langstack: self.langstack.pop() if self.langstack: # and (self.langstack[-1] is not None): self.lang = self.langstack[-1] self.depth -= 1 def handle_charref(self, ref): # called for each character reference, e.g. for ' ', ref will be '160' if not self.elementstack: return ref = ref.lower() if ref in ('34', '38', '39', '60', '62', 'x22', 'x26', 'x27', 'x3c', 'x3e'): text = '&#%s;' % ref else: if ref[0] == 'x': c = int(ref[1:], 16) else: c = int(ref) text = unichr(c).encode('utf-8') self.elementstack[-1][2].append(text) def handle_entityref(self, ref): # called for each entity reference, e.g. for '©', ref will be 'copy' if not self.elementstack: return if ref in ('lt', 'gt', 'quot', 'amp', 'apos'): text = '&%s;' % ref elif ref in self.entities: text = self.entities[ref] if text.startswith('&#') and text.endswith(';'): return self.handle_entityref(text) else: try: name2codepoint[ref] except KeyError: text = '&%s;' % ref else: text = unichr(name2codepoint[ref]).encode('utf-8') self.elementstack[-1][2].append(text) def handle_data(self, text, escape=1): # called for each block of plain text, i.e. outside of any tag and # not containing any character or entity references if not self.elementstack: return if escape and self.contentparams.get('type') == u'application/xhtml+xml': text = _xmlescape(text) self.elementstack[-1][2].append(text) def handle_comment(self, text): # called for each comment, e.g. pass def handle_pi(self, text): # called for each processing instruction, e.g. pass def handle_decl(self, text): pass def parse_declaration(self, i): # override internal declaration handler to handle CDATA blocks if self.rawdata[i:i+9] == '', i) if k == -1: # CDATA block began but didn't finish k = len(self.rawdata) return k self.handle_data(_xmlescape(self.rawdata[i+9:k]), 0) return k+3 else: k = self.rawdata.find('>', i) if k >= 0: return k+1 else: # We have an incomplete CDATA block. return k def mapContentType(self, contentType): contentType = contentType.lower() if contentType == 'text' or contentType == 'plain': contentType = u'text/plain' elif contentType == 'html': contentType = u'text/html' elif contentType == 'xhtml': contentType = u'application/xhtml+xml' return contentType def trackNamespace(self, prefix, uri): loweruri = uri.lower() if not self.version: if (prefix, loweruri) == (None, 'http://my.netscape.com/rdf/simple/0.9/'): self.version = u'rss090' elif loweruri == 'http://purl.org/rss/1.0/': self.version = u'rss10' elif loweruri == 'http://www.w3.org/2005/atom': self.version = u'atom10' if loweruri.find(u'backend.userland.com/rss') <> -1: # match any backend.userland.com namespace uri = u'http://backend.userland.com/rss' loweruri = uri if loweruri in self._matchnamespaces: self.namespacemap[prefix] = self._matchnamespaces[loweruri] self.namespacesInUse[self._matchnamespaces[loweruri]] = uri else: self.namespacesInUse[prefix or ''] = uri def resolveURI(self, uri): return _urljoin(self.baseuri or u'', uri) def decodeEntities(self, element, data): return data def strattrs(self, attrs): return ''.join([' %s="%s"' % (t[0],_xmlescape(t[1],{'"':'"'})) for t in attrs]) def push(self, element, expectingText): self.elementstack.append([element, expectingText, []]) def pop(self, element, stripWhitespace=1): if not self.elementstack: return if self.elementstack[-1][0] != element: return element, expectingText, pieces = self.elementstack.pop() if self.version == u'atom10' and self.contentparams.get('type', u'text') == u'application/xhtml+xml': # remove enclosing child element, but only if it is a
and # only if all the remaining content is nested underneath it. # This means that the divs would be retained in the following: #
foo
bar
while pieces and len(pieces)>1 and not pieces[-1].strip(): del pieces[-1] while pieces and len(pieces)>1 and not pieces[0].strip(): del pieces[0] if pieces and (pieces[0] == '
' or pieces[0].startswith('
': depth = 0 for piece in pieces[:-1]: if piece.startswith(''): depth += 1 else: pieces = pieces[1:-1] # Ensure each piece is a str for Python 3 for (i, v) in enumerate(pieces): if not isinstance(v, unicode): pieces[i] = v.decode('utf-8') output = u''.join(pieces) if stripWhitespace: output = output.strip() if not expectingText: return output # decode base64 content if base64 and self.contentparams.get('base64', 0): try: output = _base64decode(output) except binascii.Error: pass except binascii.Incomplete: pass except TypeError: # In Python 3, base64 takes and outputs bytes, not str # This may not be the most correct way to accomplish this output = _base64decode(output.encode('utf-8')).decode('utf-8') # resolve relative URIs if (element in self.can_be_relative_uri) and output: output = self.resolveURI(output) # decode entities within embedded markup if not self.contentparams.get('base64', 0): output = self.decodeEntities(element, output) # some feed formats require consumers to guess # whether the content is html or plain text if not self.version.startswith(u'atom') and self.contentparams.get('type') == u'text/plain': if self.lookslikehtml(output): self.contentparams['type'] = u'text/html' # remove temporary cruft from contentparams try: del self.contentparams['mode'] except KeyError: pass try: del self.contentparams['base64'] except KeyError: pass is_htmlish = self.mapContentType(self.contentparams.get('type', u'text/html')) in self.html_types # resolve relative URIs within embedded markup if is_htmlish and RESOLVE_RELATIVE_URIS: if element in self.can_contain_relative_uris: output = _resolveRelativeURIs(output, self.baseuri, self.encoding, self.contentparams.get('type', u'text/html')) # parse microformats # (must do this before sanitizing because some microformats # rely on elements that we sanitize) if PARSE_MICROFORMATS and is_htmlish and element in ['content', 'description', 'summary']: mfresults = _parseMicroformats(output, self.baseuri, self.encoding) if mfresults: for tag in mfresults.get('tags', []): self._addTag(tag['term'], tag['scheme'], tag['label']) for enclosure in mfresults.get('enclosures', []): self._start_enclosure(enclosure) for xfn in mfresults.get('xfn', []): self._addXFN(xfn['relationships'], xfn['href'], xfn['name']) vcard = mfresults.get('vcard') if vcard: self._getContext()['vcard'] = vcard # sanitize embedded markup if is_htmlish and SANITIZE_HTML: if element in self.can_contain_dangerous_markup: output = _sanitizeHTML(output, self.encoding, self.contentparams.get('type', u'text/html')) if self.encoding and not isinstance(output, unicode): output = output.decode(self.encoding, 'ignore') # address common error where people take data that is already # utf-8, presume that it is iso-8859-1, and re-encode it. if self.encoding in (u'utf-8', u'utf-8_INVALID_PYTHON_3') and isinstance(output, unicode): try: output = output.encode('iso-8859-1').decode('utf-8') except (UnicodeEncodeError, UnicodeDecodeError): pass # map win-1252 extensions to the proper code points if isinstance(output, unicode): output = output.translate(_cp1252) # categories/tags/keywords/whatever are handled in _end_category if element == 'category': return output if element == 'title' and -1 < self.title_depth <= self.depth: return output # store output in appropriate place(s) if self.inentry and not self.insource: if element == 'content': self.entries[-1].setdefault(element, []) contentparams = copy.deepcopy(self.contentparams) contentparams['value'] = output self.entries[-1][element].append(contentparams) elif element == 'link': if not self.inimage: # query variables in urls in link elements are improperly # converted from `?a=1&b=2` to `?a=1&b;=2` as if they're # unhandled character references. fix this special case. output = re.sub("&([A-Za-z0-9_]+);", "&\g<1>", output) self.entries[-1][element] = output if output: self.entries[-1]['links'][-1]['href'] = output else: if element == 'description': element = 'summary' old_value_depth = self.property_depth_map.setdefault(self.entries[-1], {}).get(element) if old_value_depth is None or self.depth <= old_value_depth: self.property_depth_map[self.entries[-1]][element] = self.depth self.entries[-1][element] = output if self.incontent: contentparams = copy.deepcopy(self.contentparams) contentparams['value'] = output self.entries[-1][element + '_detail'] = contentparams elif (self.infeed or self.insource):# and (not self.intextinput) and (not self.inimage): context = self._getContext() if element == 'description': element = 'subtitle' context[element] = output if element == 'link': # fix query variables; see above for the explanation output = re.sub("&([A-Za-z0-9_]+);", "&\g<1>", output) context[element] = output context['links'][-1]['href'] = output elif self.incontent: contentparams = copy.deepcopy(self.contentparams) contentparams['value'] = output context[element + '_detail'] = contentparams return output def pushContent(self, tag, attrsD, defaultContentType, expectingText): self.incontent += 1 if self.lang: self.lang=self.lang.replace('_','-') self.contentparams = FeedParserDict({ 'type': self.mapContentType(attrsD.get('type', defaultContentType)), 'language': self.lang, 'base': self.baseuri}) self.contentparams['base64'] = self._isBase64(attrsD, self.contentparams) self.push(tag, expectingText) def popContent(self, tag): value = self.pop(tag) self.incontent -= 1 self.contentparams.clear() return value # a number of elements in a number of RSS variants are nominally plain # text, but this is routinely ignored. This is an attempt to detect # the most common cases. As false positives often result in silent # data loss, this function errs on the conservative side. @staticmethod def lookslikehtml(s): # must have a close tag or an entity reference to qualify if not (re.search(r'',s) or re.search("&#?\w+;",s)): return # all tags must be in a restricted subset of valid HTML tags if filter(lambda t: t.lower() not in _HTMLSanitizer.acceptable_elements, re.findall(r' -1: prefix = name[:colonpos] suffix = name[colonpos+1:] prefix = self.namespacemap.get(prefix, prefix) name = prefix + ':' + suffix return name def _getAttribute(self, attrsD, name): return attrsD.get(self._mapToStandardPrefix(name)) def _isBase64(self, attrsD, contentparams): if attrsD.get('mode', '') == 'base64': return 1 if self.contentparams['type'].startswith(u'text/'): return 0 if self.contentparams['type'].endswith(u'+xml'): return 0 if self.contentparams['type'].endswith(u'/xml'): return 0 return 1 def _itsAnHrefDamnIt(self, attrsD): href = attrsD.get('url', attrsD.get('uri', attrsD.get('href', None))) if href: try: del attrsD['url'] except KeyError: pass try: del attrsD['uri'] except KeyError: pass attrsD['href'] = href return attrsD def _save(self, key, value, overwrite=False): context = self._getContext() if overwrite: context[key] = value else: context.setdefault(key, value) def _start_rss(self, attrsD): versionmap = {'0.91': u'rss091u', '0.92': u'rss092', '0.93': u'rss093', '0.94': u'rss094'} #If we're here then this is an RSS feed. #If we don't have a version or have a version that starts with something #other than RSS then there's been a mistake. Correct it. if not self.version or not self.version.startswith(u'rss'): attr_version = attrsD.get('version', '') version = versionmap.get(attr_version) if version: self.version = version elif attr_version.startswith('2.'): self.version = u'rss20' else: self.version = u'rss' def _start_channel(self, attrsD): self.infeed = 1 self._cdf_common(attrsD) def _cdf_common(self, attrsD): if 'lastmod' in attrsD: self._start_modified({}) self.elementstack[-1][-1] = attrsD['lastmod'] self._end_modified() if 'href' in attrsD: self._start_link({}) self.elementstack[-1][-1] = attrsD['href'] self._end_link() def _start_feed(self, attrsD): self.infeed = 1 versionmap = {'0.1': u'atom01', '0.2': u'atom02', '0.3': u'atom03'} if not self.version: attr_version = attrsD.get('version') version = versionmap.get(attr_version) if version: self.version = version else: self.version = u'atom' def _end_channel(self): self.infeed = 0 _end_feed = _end_channel def _start_image(self, attrsD): context = self._getContext() if not self.inentry: context.setdefault('image', FeedParserDict()) self.inimage = 1 self.title_depth = -1 self.push('image', 0) def _end_image(self): self.pop('image') self.inimage = 0 def _start_textinput(self, attrsD): context = self._getContext() context.setdefault('textinput', FeedParserDict()) self.intextinput = 1 self.title_depth = -1 self.push('textinput', 0) _start_textInput = _start_textinput def _end_textinput(self): self.pop('textinput') self.intextinput = 0 _end_textInput = _end_textinput def _start_author(self, attrsD): self.inauthor = 1 self.push('author', 1) # Append a new FeedParserDict when expecting an author context = self._getContext() context.setdefault('authors', []) context['authors'].append(FeedParserDict()) _start_managingeditor = _start_author _start_dc_author = _start_author _start_dc_creator = _start_author _start_itunes_author = _start_author def _end_author(self): self.pop('author') self.inauthor = 0 self._sync_author_detail() _end_managingeditor = _end_author _end_dc_author = _end_author _end_dc_creator = _end_author _end_itunes_author = _end_author def _start_itunes_owner(self, attrsD): self.inpublisher = 1 self.push('publisher', 0) def _end_itunes_owner(self): self.pop('publisher') self.inpublisher = 0 self._sync_author_detail('publisher') def _start_contributor(self, attrsD): self.incontributor = 1 context = self._getContext() context.setdefault('contributors', []) context['contributors'].append(FeedParserDict()) self.push('contributor', 0) def _end_contributor(self): self.pop('contributor') self.incontributor = 0 def _start_dc_contributor(self, attrsD): self.incontributor = 1 context = self._getContext() context.setdefault('contributors', []) context['contributors'].append(FeedParserDict()) self.push('name', 0) def _end_dc_contributor(self): self._end_name() self.incontributor = 0 def _start_name(self, attrsD): self.push('name', 0) _start_itunes_name = _start_name def _end_name(self): value = self.pop('name') if self.inpublisher: self._save_author('name', value, 'publisher') elif self.inauthor: self._save_author('name', value) elif self.incontributor: self._save_contributor('name', value) elif self.intextinput: context = self._getContext() context['name'] = value _end_itunes_name = _end_name def _start_width(self, attrsD): self.push('width', 0) def _end_width(self): value = self.pop('width') try: value = int(value) except ValueError: value = 0 if self.inimage: context = self._getContext() context['width'] = value def _start_height(self, attrsD): self.push('height', 0) def _end_height(self): value = self.pop('height') try: value = int(value) except ValueError: value = 0 if self.inimage: context = self._getContext() context['height'] = value def _start_url(self, attrsD): self.push('href', 1) _start_homepage = _start_url _start_uri = _start_url def _end_url(self): value = self.pop('href') if self.inauthor: self._save_author('href', value) elif self.incontributor: self._save_contributor('href', value) _end_homepage = _end_url _end_uri = _end_url def _start_email(self, attrsD): self.push('email', 0) _start_itunes_email = _start_email def _end_email(self): value = self.pop('email') if self.inpublisher: self._save_author('email', value, 'publisher') elif self.inauthor: self._save_author('email', value) elif self.incontributor: self._save_contributor('email', value) _end_itunes_email = _end_email def _getContext(self): if self.insource: context = self.sourcedata elif self.inimage and 'image' in self.feeddata: context = self.feeddata['image'] elif self.intextinput: context = self.feeddata['textinput'] elif self.inentry: context = self.entries[-1] else: context = self.feeddata return context def _save_author(self, key, value, prefix='author'): context = self._getContext() context.setdefault(prefix + '_detail', FeedParserDict()) context[prefix + '_detail'][key] = value self._sync_author_detail() context.setdefault('authors', [FeedParserDict()]) context['authors'][-1][key] = value def _save_contributor(self, key, value): context = self._getContext() context.setdefault('contributors', [FeedParserDict()]) context['contributors'][-1][key] = value def _sync_author_detail(self, key='author'): context = self._getContext() detail = context.get('%s_detail' % key) if detail: name = detail.get('name') email = detail.get('email') if name and email: context[key] = u'%s (%s)' % (name, email) elif name: context[key] = name elif email: context[key] = email else: author, email = context.get(key), None if not author: return emailmatch = re.search(ur'''(([a-zA-Z0-9\_\-\.\+]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?))(\?subject=\S+)?''', author) if emailmatch: email = emailmatch.group(0) # probably a better way to do the following, but it passes all the tests author = author.replace(email, u'') author = author.replace(u'()', u'') author = author.replace(u'<>', u'') author = author.replace(u'<>', u'') author = author.strip() if author and (author[0] == u'('): author = author[1:] if author and (author[-1] == u')'): author = author[:-1] author = author.strip() if author or email: context.setdefault('%s_detail' % key, FeedParserDict()) if author: context['%s_detail' % key]['name'] = author if email: context['%s_detail' % key]['email'] = email def _start_subtitle(self, attrsD): self.pushContent('subtitle', attrsD, u'text/plain', 1) _start_tagline = _start_subtitle _start_itunes_subtitle = _start_subtitle def _end_subtitle(self): self.popContent('subtitle') _end_tagline = _end_subtitle _end_itunes_subtitle = _end_subtitle def _start_rights(self, attrsD): self.pushContent('rights', attrsD, u'text/plain', 1) _start_dc_rights = _start_rights _start_copyright = _start_rights def _end_rights(self): self.popContent('rights') _end_dc_rights = _end_rights _end_copyright = _end_rights def _start_item(self, attrsD): self.entries.append(FeedParserDict()) self.push('item', 0) self.inentry = 1 self.guidislink = 0 self.title_depth = -1 id = self._getAttribute(attrsD, 'rdf:about') if id: context = self._getContext() context['id'] = id self._cdf_common(attrsD) _start_entry = _start_item def _end_item(self): self.pop('item') self.inentry = 0 _end_entry = _end_item def _start_dc_language(self, attrsD): self.push('language', 1) _start_language = _start_dc_language def _end_dc_language(self): self.lang = self.pop('language') _end_language = _end_dc_language def _start_dc_publisher(self, attrsD): self.push('publisher', 1) _start_webmaster = _start_dc_publisher def _end_dc_publisher(self): self.pop('publisher') self._sync_author_detail('publisher') _end_webmaster = _end_dc_publisher def _start_published(self, attrsD): self.push('published', 1) _start_dcterms_issued = _start_published _start_issued = _start_published _start_pubdate = _start_published def _end_published(self): value = self.pop('published') self._save('published_parsed', _parse_date(value), overwrite=True) _end_dcterms_issued = _end_published _end_issued = _end_published _end_pubdate = _end_published def _start_updated(self, attrsD): self.push('updated', 1) _start_modified = _start_updated _start_dcterms_modified = _start_updated _start_dc_date = _start_updated _start_lastbuilddate = _start_updated def _end_updated(self): value = self.pop('updated') parsed_value = _parse_date(value) self._save('updated_parsed', parsed_value, overwrite=True) _end_modified = _end_updated _end_dcterms_modified = _end_updated _end_dc_date = _end_updated _end_lastbuilddate = _end_updated def _start_created(self, attrsD): self.push('created', 1) _start_dcterms_created = _start_created def _end_created(self): value = self.pop('created') self._save('created_parsed', _parse_date(value), overwrite=True) _end_dcterms_created = _end_created def _start_expirationdate(self, attrsD): self.push('expired', 1) def _end_expirationdate(self): self._save('expired_parsed', _parse_date(self.pop('expired')), overwrite=True) def _start_cc_license(self, attrsD): context = self._getContext() value = self._getAttribute(attrsD, 'rdf:resource') attrsD = FeedParserDict() attrsD['rel'] = u'license' if value: attrsD['href']=value context.setdefault('links', []).append(attrsD) def _start_creativecommons_license(self, attrsD): self.push('license', 1) _start_creativeCommons_license = _start_creativecommons_license def _end_creativecommons_license(self): value = self.pop('license') context = self._getContext() attrsD = FeedParserDict() attrsD['rel'] = u'license' if value: attrsD['href'] = value context.setdefault('links', []).append(attrsD) del context['license'] _end_creativeCommons_license = _end_creativecommons_license def _addXFN(self, relationships, href, name): context = self._getContext() xfn = context.setdefault('xfn', []) value = FeedParserDict({'relationships': relationships, 'href': href, 'name': name}) if value not in xfn: xfn.append(value) def _addTag(self, term, scheme, label): context = self._getContext() tags = context.setdefault('tags', []) if (not term) and (not scheme) and (not label): return value = FeedParserDict({'term': term, 'scheme': scheme, 'label': label}) if value not in tags: tags.append(value) def _start_category(self, attrsD): term = attrsD.get('term') scheme = attrsD.get('scheme', attrsD.get('domain')) label = attrsD.get('label') self._addTag(term, scheme, label) self.push('category', 1) _start_dc_subject = _start_category _start_keywords = _start_category def _start_media_category(self, attrsD): attrsD.setdefault('scheme', u'http://search.yahoo.com/mrss/category_schema') self._start_category(attrsD) def _end_itunes_keywords(self): for term in self.pop('itunes_keywords').split(','): if term.strip(): self._addTag(term.strip(), u'http://www.itunes.com/', None) def _start_itunes_category(self, attrsD): self._addTag(attrsD.get('text'), u'http://www.itunes.com/', None) self.push('category', 1) def _end_category(self): value = self.pop('category') if not value: return context = self._getContext() tags = context['tags'] if value and len(tags) and not tags[-1]['term']: tags[-1]['term'] = value else: self._addTag(value, None, None) _end_dc_subject = _end_category _end_keywords = _end_category _end_itunes_category = _end_category _end_media_category = _end_category def _start_cloud(self, attrsD): self._getContext()['cloud'] = FeedParserDict(attrsD) def _start_link(self, attrsD): attrsD.setdefault('rel', u'alternate') if attrsD['rel'] == u'self': attrsD.setdefault('type', u'application/atom+xml') else: attrsD.setdefault('type', u'text/html') context = self._getContext() attrsD = self._itsAnHrefDamnIt(attrsD) if 'href' in attrsD: attrsD['href'] = self.resolveURI(attrsD['href']) expectingText = self.infeed or self.inentry or self.insource context.setdefault('links', []) if not (self.inentry and self.inimage): context['links'].append(FeedParserDict(attrsD)) if 'href' in attrsD: expectingText = 0 if (attrsD.get('rel') == u'alternate') and (self.mapContentType(attrsD.get('type')) in self.html_types): context['link'] = attrsD['href'] else: self.push('link', expectingText) def _end_link(self): value = self.pop('link') def _start_guid(self, attrsD): self.guidislink = (attrsD.get('ispermalink', 'true') == 'true') self.push('id', 1) _start_id = _start_guid def _end_guid(self): value = self.pop('id') self._save('guidislink', self.guidislink and 'link' not in self._getContext()) if self.guidislink: # guid acts as link, but only if 'ispermalink' is not present or is 'true', # and only if the item doesn't already have a link element self._save('link', value) _end_id = _end_guid def _start_title(self, attrsD): if self.svgOK: return self.unknown_starttag('title', attrsD.items()) self.pushContent('title', attrsD, u'text/plain', self.infeed or self.inentry or self.insource) _start_dc_title = _start_title _start_media_title = _start_title def _end_title(self): if self.svgOK: return value = self.popContent('title') if not value: return self.title_depth = self.depth _end_dc_title = _end_title def _end_media_title(self): title_depth = self.title_depth self._end_title() self.title_depth = title_depth def _start_description(self, attrsD): context = self._getContext() if 'summary' in context: self._summaryKey = 'content' self._start_content(attrsD) else: self.pushContent('description', attrsD, u'text/html', self.infeed or self.inentry or self.insource) _start_dc_description = _start_description def _start_abstract(self, attrsD): self.pushContent('description', attrsD, u'text/plain', self.infeed or self.inentry or self.insource) def _end_description(self): if self._summaryKey == 'content': self._end_content() else: value = self.popContent('description') self._summaryKey = None _end_abstract = _end_description _end_dc_description = _end_description def _start_info(self, attrsD): self.pushContent('info', attrsD, u'text/plain', 1) _start_feedburner_browserfriendly = _start_info def _end_info(self): self.popContent('info') _end_feedburner_browserfriendly = _end_info def _start_generator(self, attrsD): if attrsD: attrsD = self._itsAnHrefDamnIt(attrsD) if 'href' in attrsD: attrsD['href'] = self.resolveURI(attrsD['href']) self._getContext()['generator_detail'] = FeedParserDict(attrsD) self.push('generator', 1) def _end_generator(self): value = self.pop('generator') context = self._getContext() if 'generator_detail' in context: context['generator_detail']['name'] = value def _start_admin_generatoragent(self, attrsD): self.push('generator', 1) value = self._getAttribute(attrsD, 'rdf:resource') if value: self.elementstack[-1][2].append(value) self.pop('generator') self._getContext()['generator_detail'] = FeedParserDict({'href': value}) def _start_admin_errorreportsto(self, attrsD): self.push('errorreportsto', 1) value = self._getAttribute(attrsD, 'rdf:resource') if value: self.elementstack[-1][2].append(value) self.pop('errorreportsto') def _start_summary(self, attrsD): context = self._getContext() if 'summary' in context: self._summaryKey = 'content' self._start_content(attrsD) else: self._summaryKey = 'summary' self.pushContent(self._summaryKey, attrsD, u'text/plain', 1) _start_itunes_summary = _start_summary def _end_summary(self): if self._summaryKey == 'content': self._end_content() else: self.popContent(self._summaryKey or 'summary') self._summaryKey = None _end_itunes_summary = _end_summary def _start_enclosure(self, attrsD): attrsD = self._itsAnHrefDamnIt(attrsD) context = self._getContext() attrsD['rel'] = u'enclosure' context.setdefault('links', []).append(FeedParserDict(attrsD)) def _start_source(self, attrsD): if 'url' in attrsD: # This means that we're processing a source element from an RSS 2.0 feed self.sourcedata['href'] = attrsD[u'url'] self.push('source', 1) self.insource = 1 self.title_depth = -1 def _end_source(self): self.insource = 0 value = self.pop('source') if value: self.sourcedata['title'] = value self._getContext()['source'] = copy.deepcopy(self.sourcedata) self.sourcedata.clear() def _start_content(self, attrsD): self.pushContent('content', attrsD, u'text/plain', 1) src = attrsD.get('src') if src: self.contentparams['src'] = src self.push('content', 1) def _start_body(self, attrsD): self.pushContent('content', attrsD, u'application/xhtml+xml', 1) _start_xhtml_body = _start_body def _start_content_encoded(self, attrsD): self.pushContent('content', attrsD, u'text/html', 1) _start_fullitem = _start_content_encoded def _end_content(self): copyToSummary = self.mapContentType(self.contentparams.get('type')) in ([u'text/plain'] + self.html_types) value = self.popContent('content') if copyToSummary: self._save('summary', value) _end_body = _end_content _end_xhtml_body = _end_content _end_content_encoded = _end_content _end_fullitem = _end_content def _start_itunes_image(self, attrsD): self.push('itunes_image', 0) if attrsD.get('href'): self._getContext()['image'] = FeedParserDict({'href': attrsD.get('href')}) elif attrsD.get('url'): self._getContext()['image'] = FeedParserDict({'href': attrsD.get('url')}) _start_itunes_link = _start_itunes_image def _end_itunes_block(self): value = self.pop('itunes_block', 0) self._getContext()['itunes_block'] = (value == 'yes') and 1 or 0 def _end_itunes_explicit(self): value = self.pop('itunes_explicit', 0) # Convert 'yes' -> True, 'clean' to False, and any other value to None # False and None both evaluate as False, so the difference can be ignored # by applications that only need to know if the content is explicit. self._getContext()['itunes_explicit'] = (None, False, True)[(value == 'yes' and 2) or value == 'clean' or 0] def _start_media_content(self, attrsD): context = self._getContext() context.setdefault('media_content', []) context['media_content'].append(attrsD) def _start_media_thumbnail(self, attrsD): context = self._getContext() context.setdefault('media_thumbnail', []) self.push('url', 1) # new context['media_thumbnail'].append(attrsD) def _end_media_thumbnail(self): url = self.pop('url') context = self._getContext() if url != None and len(url.strip()) != 0: if 'url' not in context['media_thumbnail'][-1]: context['media_thumbnail'][-1]['url'] = url def _start_media_player(self, attrsD): self.push('media_player', 0) self._getContext()['media_player'] = FeedParserDict(attrsD) def _end_media_player(self): value = self.pop('media_player') context = self._getContext() context['media_player']['content'] = value def _start_newlocation(self, attrsD): self.push('newlocation', 1) def _end_newlocation(self): url = self.pop('newlocation') context = self._getContext() # don't set newlocation if the context isn't right if context is not self.feeddata: return context['newlocation'] = _makeSafeAbsoluteURI(self.baseuri, url.strip()) def _start_newznab_attr(self, attrsD): context = self._getContext() # Add the dict if 'newznab' not in context: context['newznab'] = {} # Don't crash when it fails try: # Add keys context['newznab'][attrsD['name']] = attrsD['value'] # Try to get date-object if attrsD['name'] == 'usenetdate': context['newznab'][attrsD['name'] + '_parsed'] = _parse_date(attrsD['value']) except KeyError: pass _start_nZEDb_attr = _start_newznab_attr _start_nzedb_attr = _start_newznab_attr _start_nntmux_attr = _start_newznab_attr if _XML_AVAILABLE: class _StrictFeedParser(_FeedParserMixin, xml.sax.handler.ContentHandler): def __init__(self, baseuri, baselang, encoding): xml.sax.handler.ContentHandler.__init__(self) _FeedParserMixin.__init__(self, baseuri, baselang, encoding) self.bozo = 0 self.exc = None self.decls = {} def startPrefixMapping(self, prefix, uri): if not uri: return # Jython uses '' instead of None; standardize on None prefix = prefix or None self.trackNamespace(prefix, uri) if prefix and uri == 'http://www.w3.org/1999/xlink': self.decls['xmlns:' + prefix] = uri def startElementNS(self, name, qname, attrs): namespace, localname = name lowernamespace = str(namespace or '').lower() if lowernamespace.find(u'backend.userland.com/rss') <> -1: # match any backend.userland.com namespace namespace = u'http://backend.userland.com/rss' lowernamespace = namespace if qname and qname.find(':') > 0: givenprefix = qname.split(':')[0] else: givenprefix = None prefix = self._matchnamespaces.get(lowernamespace, givenprefix) if givenprefix and (prefix == None or (prefix == '' and lowernamespace == '')) and givenprefix not in self.namespacesInUse: raise UndeclaredNamespace, "'%s' is not associated with a namespace" % givenprefix localname = str(localname).lower() # qname implementation is horribly broken in Python 2.1 (it # doesn't report any), and slightly broken in Python 2.2 (it # doesn't report the xml: namespace). So we match up namespaces # with a known list first, and then possibly override them with # the qnames the SAX parser gives us (if indeed it gives us any # at all). Thanks to MatejC for helping me test this and # tirelessly telling me that it didn't work yet. attrsD, self.decls = self.decls, {} if localname=='math' and namespace=='http://www.w3.org/1998/Math/MathML': attrsD['xmlns']=namespace if localname=='svg' and namespace=='http://www.w3.org/2000/svg': attrsD['xmlns']=namespace if prefix: localname = prefix.lower() + ':' + localname elif namespace and not qname: #Expat for name,value in self.namespacesInUse.items(): if name and value == namespace: localname = name + ':' + localname break for (namespace, attrlocalname), attrvalue in attrs.items(): lowernamespace = (namespace or '').lower() prefix = self._matchnamespaces.get(lowernamespace, '') if prefix: attrlocalname = prefix + ':' + attrlocalname attrsD[str(attrlocalname).lower()] = attrvalue for qname in attrs.getQNames(): attrsD[str(qname).lower()] = attrs.getValueByQName(qname) self.unknown_starttag(localname, attrsD.items()) def characters(self, text): self.handle_data(text) def endElementNS(self, name, qname): namespace, localname = name lowernamespace = str(namespace or '').lower() if qname and qname.find(':') > 0: givenprefix = qname.split(':')[0] else: givenprefix = '' prefix = self._matchnamespaces.get(lowernamespace, givenprefix) if prefix: localname = prefix + ':' + localname elif namespace and not qname: #Expat for name,value in self.namespacesInUse.items(): if name and value == namespace: localname = name + ':' + localname break localname = str(localname).lower() self.unknown_endtag(localname) def error(self, exc): self.bozo = 1 self.exc = exc # drv_libxml2 calls warning() in some cases warning = error def fatalError(self, exc): self.error(exc) raise exc class _BaseHTMLProcessor(sgmllib.SGMLParser): special = re.compile('''[<>'"]''') bare_ampersand = re.compile("&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)") elements_no_end_tag = set([ 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr' ]) def __init__(self, encoding, _type): self.encoding = encoding self._type = _type sgmllib.SGMLParser.__init__(self) def reset(self): self.pieces = [] sgmllib.SGMLParser.reset(self) def _shorttag_replace(self, match): tag = match.group(1) if tag in self.elements_no_end_tag: return '<' + tag + ' />' else: return '<' + tag + '>' # By declaring these methods and overriding their compiled code # with the code from sgmllib, the original code will execute in # feedparser's scope instead of sgmllib's. This means that the # `tagfind` and `charref` regular expressions will be found as # they're declared above, not as they're declared in sgmllib. def goahead(self, i): pass goahead.func_code = sgmllib.SGMLParser.goahead.func_code def __parse_starttag(self, i): pass __parse_starttag.func_code = sgmllib.SGMLParser.parse_starttag.func_code def parse_starttag(self,i): j = self.__parse_starttag(i) if self._type == 'application/xhtml+xml': if j>2 and self.rawdata[j-2:j]=='/>': self.unknown_endtag(self.lasttag) return j def feed(self, data): data = re.compile(r'\s]+?)\s*/>', self._shorttag_replace, data) data = data.replace(''', "'") data = data.replace('"', '"') try: bytes if bytes is str: raise NameError self.encoding = self.encoding + u'_INVALID_PYTHON_3' except NameError: if self.encoding and isinstance(data, unicode): data = data.encode(self.encoding) sgmllib.SGMLParser.feed(self, data) sgmllib.SGMLParser.close(self) def normalize_attrs(self, attrs): if not attrs: return attrs # utility method to be called by descendants attrs = dict([(k.lower(), v) for k, v in attrs]).items() attrs = [(k, k in ('rel', 'type') and v.lower() or v) for k, v in attrs] attrs.sort() return attrs def unknown_starttag(self, tag, attrs): # called for each start tag # attrs is a list of (attr, value) tuples # e.g. for
, tag='pre', attrs=[('class', 'screen')]
        uattrs = []
        strattrs=''
        if attrs:
            for key, value in attrs:
                value=value.replace('>','>').replace('<','<').replace('"','"')
                value = self.bare_ampersand.sub("&", value)
                # thanks to Kevin Marks for this breathtaking hack to deal with (valid) high-bit attribute values in UTF-8 feeds
                if not isinstance(value, unicode):
                    value = value.decode(self.encoding, 'ignore')
                try:
                    # Currently, in Python 3 the key is already a str, and cannot be decoded again
                    uattrs.append((unicode(key, self.encoding), value))
                except TypeError:
                    uattrs.append((key, value))
            strattrs = u''.join([u' %s="%s"' % (key, value) for key, value in uattrs])
            if self.encoding:
                try:
                    strattrs = strattrs.encode(self.encoding)
                except (UnicodeEncodeError, LookupError):
                    pass
        if tag in self.elements_no_end_tag:
            self.pieces.append('<%s%s />' % (tag, strattrs))
        else:
            self.pieces.append('<%s%s>' % (tag, strattrs))

    def unknown_endtag(self, tag):
        # called for each end tag, e.g. for 
, tag will be 'pre' # Reconstruct the original end tag. if tag not in self.elements_no_end_tag: self.pieces.append("" % tag) def handle_charref(self, ref): # called for each character reference, e.g. for ' ', ref will be '160' # Reconstruct the original character reference. ref = ref.lower() if ref.startswith('x'): value = int(ref[1:], 16) else: value = int(ref) if value in _cp1252: self.pieces.append('&#%s;' % hex(ord(_cp1252[value]))[1:]) else: self.pieces.append('&#%s;' % ref) def handle_entityref(self, ref): # called for each entity reference, e.g. for '©', ref will be 'copy' # Reconstruct the original entity reference. if ref in name2codepoint or ref == 'apos': self.pieces.append('&%s;' % ref) else: self.pieces.append('&%s' % ref) def handle_data(self, text): # called for each block of plain text, i.e. outside of any tag and # not containing any character or entity references # Store the original text verbatim. self.pieces.append(text) def handle_comment(self, text): # called for each HTML comment, e.g. # Reconstruct the original comment. self.pieces.append('' % text) def handle_pi(self, text): # called for each processing instruction, e.g. # Reconstruct original processing instruction. self.pieces.append('' % text) def handle_decl(self, text): # called for the DOCTYPE, if present, e.g. # # Reconstruct original DOCTYPE self.pieces.append('' % text) _new_declname_match = re.compile(r'[a-zA-Z][-_.a-zA-Z0-9:]*\s*').match def _scan_name(self, i, declstartpos): rawdata = self.rawdata n = len(rawdata) if i == n: return None, -1 m = self._new_declname_match(rawdata, i) if m: s = m.group() name = s.strip() if (i + len(s)) == n: return None, -1 # end of buffer return name.lower(), m.end() else: self.handle_data(rawdata) # self.updatepos(declstartpos, i) return None, -1 def convert_charref(self, name): return '&#%s;' % name def convert_entityref(self, name): return '&%s;' % name def output(self): '''Return processed HTML as a single string''' return ''.join([str(p) for p in self.pieces]) def parse_declaration(self, i): try: return sgmllib.SGMLParser.parse_declaration(self, i) except sgmllib.SGMLParseError: # escape the doctype declaration and continue parsing self.handle_data('<') return i+1 class _LooseFeedParser(_FeedParserMixin, _BaseHTMLProcessor): def __init__(self, baseuri, baselang, encoding, entities): sgmllib.SGMLParser.__init__(self) _FeedParserMixin.__init__(self, baseuri, baselang, encoding) _BaseHTMLProcessor.__init__(self, encoding, 'application/xhtml+xml') self.entities=entities def decodeEntities(self, element, data): data = data.replace('<', '<') data = data.replace('<', '<') data = data.replace('<', '<') data = data.replace('>', '>') data = data.replace('>', '>') data = data.replace('>', '>') data = data.replace('&', '&') data = data.replace('&', '&') data = data.replace('"', '"') data = data.replace('"', '"') data = data.replace(''', ''') data = data.replace(''', ''') if not self.contentparams.get('type', u'xml').endswith(u'xml'): data = data.replace('<', '<') data = data.replace('>', '>') data = data.replace('&', '&') data = data.replace('"', '"') data = data.replace(''', "'") return data def strattrs(self, attrs): return ''.join([' %s="%s"' % (n,v.replace('"','"')) for n,v in attrs]) class _MicroformatsParser: STRING = 1 DATE = 2 URI = 3 NODE = 4 EMAIL = 5 known_xfn_relationships = set(['contact', 'acquaintance', 'friend', 'met', 'co-worker', 'coworker', 'colleague', 'co-resident', 'coresident', 'neighbor', 'child', 'parent', 'sibling', 'brother', 'sister', 'spouse', 'wife', 'husband', 'kin', 'relative', 'muse', 'crush', 'date', 'sweetheart', 'me']) known_binary_extensions = set(['zip','rar','exe','gz','tar','tgz','tbz2','bz2','z','7z','dmg','img','sit','sitx','hqx','deb','rpm','bz2','jar','rar','iso','bin','msi','mp2','mp3','ogg','ogm','mp4','m4v','m4a','avi','wma','wmv']) def __init__(self, data, baseuri, encoding): self.document = BeautifulSoup.BeautifulSoup(data) self.baseuri = baseuri self.encoding = encoding if isinstance(data, unicode): data = data.encode(encoding) self.tags = [] self.enclosures = [] self.xfn = [] self.vcard = None def vcardEscape(self, s): if isinstance(s, basestring): s = s.replace(',', '\\,').replace(';', '\\;').replace('\n', '\\n') return s def vcardFold(self, s): s = re.sub(';+$', '', s) sFolded = '' iMax = 75 sPrefix = '' while len(s) > iMax: sFolded += sPrefix + s[:iMax] + '\n' s = s[iMax:] sPrefix = ' ' iMax = 74 sFolded += sPrefix + s return sFolded def normalize(self, s): return re.sub(r'\s+', ' ', s).strip() def unique(self, aList): results = [] for element in aList: if element not in results: results.append(element) return results def toISO8601(self, dt): return time.strftime('%Y-%m-%dT%H:%M:%SZ', dt) def getPropertyValue(self, elmRoot, sProperty, iPropertyType=4, bAllowMultiple=0, bAutoEscape=0): all = lambda x: 1 sProperty = sProperty.lower() bFound = 0 bNormalize = 1 propertyMatch = {'class': re.compile(r'\b%s\b' % sProperty)} if bAllowMultiple and (iPropertyType != self.NODE): snapResults = [] containers = elmRoot(['ul', 'ol'], propertyMatch) for container in containers: snapResults.extend(container('li')) bFound = (len(snapResults) != 0) if not bFound: snapResults = elmRoot(all, propertyMatch) bFound = (len(snapResults) != 0) if (not bFound) and (sProperty == 'value'): snapResults = elmRoot('pre') bFound = (len(snapResults) != 0) bNormalize = not bFound if not bFound: snapResults = [elmRoot] bFound = (len(snapResults) != 0) arFilter = [] if sProperty == 'vcard': snapFilter = elmRoot(all, propertyMatch) for node in snapFilter: if node.findParent(all, propertyMatch): arFilter.append(node) arResults = [] for node in snapResults: if node not in arFilter: arResults.append(node) bFound = (len(arResults) != 0) if not bFound: if bAllowMultiple: return [] elif iPropertyType == self.STRING: return '' elif iPropertyType == self.DATE: return None elif iPropertyType == self.URI: return '' elif iPropertyType == self.NODE: return None else: return None arValues = [] for elmResult in arResults: sValue = None if iPropertyType == self.NODE: if bAllowMultiple: arValues.append(elmResult) continue else: return elmResult sNodeName = elmResult.name.lower() if (iPropertyType == self.EMAIL) and (sNodeName == 'a'): sValue = (elmResult.get('href') or '').split('mailto:').pop().split('?')[0] if sValue: sValue = bNormalize and self.normalize(sValue) or sValue.strip() if (not sValue) and (sNodeName == 'abbr'): sValue = elmResult.get('title') if sValue: sValue = bNormalize and self.normalize(sValue) or sValue.strip() if (not sValue) and (iPropertyType == self.URI): if sNodeName == 'a': sValue = elmResult.get('href') elif sNodeName == 'img': sValue = elmResult.get('src') elif sNodeName == 'object': sValue = elmResult.get('data') if sValue: sValue = bNormalize and self.normalize(sValue) or sValue.strip() if (not sValue) and (sNodeName == 'img'): sValue = elmResult.get('alt') if sValue: sValue = bNormalize and self.normalize(sValue) or sValue.strip() if not sValue: sValue = elmResult.renderContents() sValue = re.sub(r'<\S[^>]*>', '', sValue) sValue = sValue.replace('\r\n', '\n') sValue = sValue.replace('\r', '\n') if sValue: sValue = bNormalize and self.normalize(sValue) or sValue.strip() if not sValue: continue if iPropertyType == self.DATE: sValue = _parse_date_iso8601(sValue) if bAllowMultiple: arValues.append(bAutoEscape and self.vcardEscape(sValue) or sValue) else: return bAutoEscape and self.vcardEscape(sValue) or sValue return arValues def findVCards(self, elmRoot, bAgentParsing=0): sVCards = '' if not bAgentParsing: arCards = self.getPropertyValue(elmRoot, 'vcard', bAllowMultiple=1) else: arCards = [elmRoot] for elmCard in arCards: arLines = [] def processSingleString(sProperty): sValue = self.getPropertyValue(elmCard, sProperty, self.STRING, bAutoEscape=1).decode(self.encoding) if sValue: arLines.append(self.vcardFold(sProperty.upper() + ':' + sValue)) return sValue or u'' def processSingleURI(sProperty): sValue = self.getPropertyValue(elmCard, sProperty, self.URI) if sValue: sContentType = '' sEncoding = '' sValueKey = '' if sValue.startswith('data:'): sEncoding = ';ENCODING=b' sContentType = sValue.split(';')[0].split('/').pop() sValue = sValue.split(',', 1).pop() else: elmValue = self.getPropertyValue(elmCard, sProperty) if elmValue: if sProperty != 'url': sValueKey = ';VALUE=uri' sContentType = elmValue.get('type', '').strip().split('/').pop().strip() sContentType = sContentType.upper() if sContentType == 'OCTET-STREAM': sContentType = '' if sContentType: sContentType = ';TYPE=' + sContentType.upper() arLines.append(self.vcardFold(sProperty.upper() + sEncoding + sContentType + sValueKey + ':' + sValue)) def processTypeValue(sProperty, arDefaultType, arForceType=None): arResults = self.getPropertyValue(elmCard, sProperty, bAllowMultiple=1) for elmResult in arResults: arType = self.getPropertyValue(elmResult, 'type', self.STRING, 1, 1) if arForceType: arType = self.unique(arForceType + arType) if not arType: arType = arDefaultType sValue = self.getPropertyValue(elmResult, 'value', self.EMAIL, 0) if sValue: arLines.append(self.vcardFold(sProperty.upper() + ';TYPE=' + ','.join(arType) + ':' + sValue)) # AGENT # must do this before all other properties because it is destructive # (removes nested class="vcard" nodes so they don't interfere with # this vcard's other properties) arAgent = self.getPropertyValue(elmCard, 'agent', bAllowMultiple=1) for elmAgent in arAgent: if re.compile(r'\bvcard\b').search(elmAgent.get('class')): sAgentValue = self.findVCards(elmAgent, 1) + '\n' sAgentValue = sAgentValue.replace('\n', '\\n') sAgentValue = sAgentValue.replace(';', '\\;') if sAgentValue: arLines.append(self.vcardFold('AGENT:' + sAgentValue)) # Completely remove the agent element from the parse tree elmAgent.extract() else: sAgentValue = self.getPropertyValue(elmAgent, 'value', self.URI, bAutoEscape=1); if sAgentValue: arLines.append(self.vcardFold('AGENT;VALUE=uri:' + sAgentValue)) # FN (full name) sFN = processSingleString('fn') # N (name) elmName = self.getPropertyValue(elmCard, 'n') if elmName: sFamilyName = self.getPropertyValue(elmName, 'family-name', self.STRING, bAutoEscape=1) sGivenName = self.getPropertyValue(elmName, 'given-name', self.STRING, bAutoEscape=1) arAdditionalNames = self.getPropertyValue(elmName, 'additional-name', self.STRING, 1, 1) + self.getPropertyValue(elmName, 'additional-names', self.STRING, 1, 1) arHonorificPrefixes = self.getPropertyValue(elmName, 'honorific-prefix', self.STRING, 1, 1) + self.getPropertyValue(elmName, 'honorific-prefixes', self.STRING, 1, 1) arHonorificSuffixes = self.getPropertyValue(elmName, 'honorific-suffix', self.STRING, 1, 1) + self.getPropertyValue(elmName, 'honorific-suffixes', self.STRING, 1, 1) arLines.append(self.vcardFold('N:' + sFamilyName + ';' + sGivenName + ';' + ','.join(arAdditionalNames) + ';' + ','.join(arHonorificPrefixes) + ';' + ','.join(arHonorificSuffixes))) elif sFN: # implied "N" optimization # http://microformats.org/wiki/hcard#Implied_.22N.22_Optimization arNames = self.normalize(sFN).split() if len(arNames) == 2: bFamilyNameFirst = (arNames[0].endswith(',') or len(arNames[1]) == 1 or ((len(arNames[1]) == 2) and (arNames[1].endswith('.')))) if bFamilyNameFirst: arLines.append(self.vcardFold('N:' + arNames[0] + ';' + arNames[1])) else: arLines.append(self.vcardFold('N:' + arNames[1] + ';' + arNames[0])) # SORT-STRING sSortString = self.getPropertyValue(elmCard, 'sort-string', self.STRING, bAutoEscape=1) if sSortString: arLines.append(self.vcardFold('SORT-STRING:' + sSortString)) # NICKNAME arNickname = self.getPropertyValue(elmCard, 'nickname', self.STRING, 1, 1) if arNickname: arLines.append(self.vcardFold('NICKNAME:' + ','.join(arNickname))) # PHOTO processSingleURI('photo') # BDAY dtBday = self.getPropertyValue(elmCard, 'bday', self.DATE) if dtBday: arLines.append(self.vcardFold('BDAY:' + self.toISO8601(dtBday))) # ADR (address) arAdr = self.getPropertyValue(elmCard, 'adr', bAllowMultiple=1) for elmAdr in arAdr: arType = self.getPropertyValue(elmAdr, 'type', self.STRING, 1, 1) if not arType: arType = ['intl','postal','parcel','work'] # default adr types, see RFC 2426 section 3.2.1 sPostOfficeBox = self.getPropertyValue(elmAdr, 'post-office-box', self.STRING, 0, 1) sExtendedAddress = self.getPropertyValue(elmAdr, 'extended-address', self.STRING, 0, 1) sStreetAddress = self.getPropertyValue(elmAdr, 'street-address', self.STRING, 0, 1) sLocality = self.getPropertyValue(elmAdr, 'locality', self.STRING, 0, 1) sRegion = self.getPropertyValue(elmAdr, 'region', self.STRING, 0, 1) sPostalCode = self.getPropertyValue(elmAdr, 'postal-code', self.STRING, 0, 1) sCountryName = self.getPropertyValue(elmAdr, 'country-name', self.STRING, 0, 1) arLines.append(self.vcardFold('ADR;TYPE=' + ','.join(arType) + ':' + sPostOfficeBox + ';' + sExtendedAddress + ';' + sStreetAddress + ';' + sLocality + ';' + sRegion + ';' + sPostalCode + ';' + sCountryName)) # LABEL processTypeValue('label', ['intl','postal','parcel','work']) # TEL (phone number) processTypeValue('tel', ['voice']) # EMAIL processTypeValue('email', ['internet'], ['internet']) # MAILER processSingleString('mailer') # TZ (timezone) processSingleString('tz') # GEO (geographical information) elmGeo = self.getPropertyValue(elmCard, 'geo') if elmGeo: sLatitude = self.getPropertyValue(elmGeo, 'latitude', self.STRING, 0, 1) sLongitude = self.getPropertyValue(elmGeo, 'longitude', self.STRING, 0, 1) arLines.append(self.vcardFold('GEO:' + sLatitude + ';' + sLongitude)) # TITLE processSingleString('title') # ROLE processSingleString('role') # LOGO processSingleURI('logo') # ORG (organization) elmOrg = self.getPropertyValue(elmCard, 'org') if elmOrg: sOrganizationName = self.getPropertyValue(elmOrg, 'organization-name', self.STRING, 0, 1) if not sOrganizationName: # implied "organization-name" optimization # http://microformats.org/wiki/hcard#Implied_.22organization-name.22_Optimization sOrganizationName = self.getPropertyValue(elmCard, 'org', self.STRING, 0, 1) if sOrganizationName: arLines.append(self.vcardFold('ORG:' + sOrganizationName)) else: arOrganizationUnit = self.getPropertyValue(elmOrg, 'organization-unit', self.STRING, 1, 1) arLines.append(self.vcardFold('ORG:' + sOrganizationName + ';' + ';'.join(arOrganizationUnit))) # CATEGORY arCategory = self.getPropertyValue(elmCard, 'category', self.STRING, 1, 1) + self.getPropertyValue(elmCard, 'categories', self.STRING, 1, 1) if arCategory: arLines.append(self.vcardFold('CATEGORIES:' + ','.join(arCategory))) # NOTE processSingleString('note') # REV processSingleString('rev') # SOUND processSingleURI('sound') # UID processSingleString('uid') # URL processSingleURI('url') # CLASS processSingleString('class') # KEY processSingleURI('key') if arLines: arLines = [u'BEGIN:vCard',u'VERSION:3.0'] + arLines + [u'END:vCard'] # XXX - this is super ugly; properly fix this with issue 148 for i, s in enumerate(arLines): if not isinstance(s, unicode): arLines[i] = s.decode('utf-8', 'ignore') sVCards += u'\n'.join(arLines) + u'\n' return sVCards.strip() def isProbablyDownloadable(self, elm): attrsD = elm.attrMap if 'href' not in attrsD: return 0 linktype = attrsD.get('type', '').strip() if linktype.startswith('audio/') or \ linktype.startswith('video/') or \ (linktype.startswith('application/') and not linktype.endswith('xml')): return 1 try: path = urlparse.urlparse(attrsD['href'])[2] except ValueError: return 0 if path.find('.') == -1: return 0 fileext = path.split('.').pop().lower() return fileext in self.known_binary_extensions def findTags(self): all = lambda x: 1 for elm in self.document(all, {'rel': re.compile(r'\btag\b')}): href = elm.get('href') if not href: continue urlscheme, domain, path, params, query, fragment = \ urlparse.urlparse(_urljoin(self.baseuri, href)) segments = path.split('/') tag = segments.pop() if not tag: if segments: tag = segments.pop() else: # there are no tags continue tagscheme = urlparse.urlunparse((urlscheme, domain, '/'.join(segments), '', '', '')) if not tagscheme.endswith('/'): tagscheme += '/' self.tags.append(FeedParserDict({"term": tag, "scheme": tagscheme, "label": elm.string or ''})) def findEnclosures(self): all = lambda x: 1 enclosure_match = re.compile(r'\benclosure\b') for elm in self.document(all, {'href': re.compile(r'.+')}): if not enclosure_match.search(elm.get('rel', u'')) and not self.isProbablyDownloadable(elm): continue if elm.attrMap not in self.enclosures: self.enclosures.append(elm.attrMap) if elm.string and not elm.get('title'): self.enclosures[-1]['title'] = elm.string def findXFN(self): all = lambda x: 1 for elm in self.document(all, {'rel': re.compile('.+'), 'href': re.compile('.+')}): rels = elm.get('rel', u'').split() xfn_rels = [r for r in rels if r in self.known_xfn_relationships] if xfn_rels: self.xfn.append({"relationships": xfn_rels, "href": elm.get('href', ''), "name": elm.string}) def _parseMicroformats(htmlSource, baseURI, encoding): if not BeautifulSoup: return try: p = _MicroformatsParser(htmlSource, baseURI, encoding) except UnicodeEncodeError: # sgmllib throws this exception when performing lookups of tags # with non-ASCII characters in them. return p.vcard = p.findVCards(p.document) p.findTags() p.findEnclosures() p.findXFN() return {"tags": p.tags, "enclosures": p.enclosures, "xfn": p.xfn, "vcard": p.vcard} class _RelativeURIResolver(_BaseHTMLProcessor): relative_uris = set([('a', 'href'), ('applet', 'codebase'), ('area', 'href'), ('blockquote', 'cite'), ('body', 'background'), ('del', 'cite'), ('form', 'action'), ('frame', 'longdesc'), ('frame', 'src'), ('iframe', 'longdesc'), ('iframe', 'src'), ('head', 'profile'), ('img', 'longdesc'), ('img', 'src'), ('img', 'usemap'), ('input', 'src'), ('input', 'usemap'), ('ins', 'cite'), ('link', 'href'), ('object', 'classid'), ('object', 'codebase'), ('object', 'data'), ('object', 'usemap'), ('q', 'cite'), ('script', 'src'), ('video', 'poster')]) def __init__(self, baseuri, encoding, _type): _BaseHTMLProcessor.__init__(self, encoding, _type) self.baseuri = baseuri def resolveURI(self, uri): return _makeSafeAbsoluteURI(self.baseuri, uri.strip()) def unknown_starttag(self, tag, attrs): attrs = self.normalize_attrs(attrs) attrs = [(key, ((tag, key) in self.relative_uris) and self.resolveURI(value) or value) for key, value in attrs] _BaseHTMLProcessor.unknown_starttag(self, tag, attrs) def _resolveRelativeURIs(htmlSource, baseURI, encoding, _type): if not _SGML_AVAILABLE: return htmlSource p = _RelativeURIResolver(baseURI, encoding, _type) p.feed(htmlSource) return p.output() def _makeSafeAbsoluteURI(base, rel=None): # bail if ACCEPTABLE_URI_SCHEMES is empty if not ACCEPTABLE_URI_SCHEMES: try: return _urljoin(base, rel or u'') except ValueError: return u'' if not base: return rel or u'' if not rel: try: scheme = urlparse.urlparse(base)[0] except ValueError: return u'' if not scheme or scheme in ACCEPTABLE_URI_SCHEMES: return base return u'' try: uri = _urljoin(base, rel) except ValueError: return u'' if uri.strip().split(':', 1)[0] not in ACCEPTABLE_URI_SCHEMES: return u'' return uri class _HTMLSanitizer(_BaseHTMLProcessor): acceptable_elements = set(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'big', 'blockquote', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', 'datagrid', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'event-source', 'fieldset', 'figcaption', 'figure', 'footer', 'font', 'form', 'header', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'input', 'ins', 'keygen', 'kbd', 'label', 'legend', 'li', 'm', 'map', 'menu', 'meter', 'multicol', 'nav', 'nextid', 'ol', 'output', 'optgroup', 'option', 'p', 'pre', 'progress', 'q', 's', 'samp', 'section', 'select', 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video', 'noscript']) acceptable_attributes = set(['abbr', 'accept', 'accept-charset', 'accesskey', 'action', 'align', 'alt', 'autocomplete', 'autofocus', 'axis', 'background', 'balance', 'bgcolor', 'bgproperties', 'border', 'bordercolor', 'bordercolordark', 'bordercolorlight', 'bottompadding', 'cellpadding', 'cellspacing', 'ch', 'challenge', 'char', 'charoff', 'choff', 'charset', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'compact', 'contenteditable', 'controls', 'coords', 'data', 'datafld', 'datapagesize', 'datasrc', 'datetime', 'default', 'delay', 'dir', 'disabled', 'draggable', 'dynsrc', 'enctype', 'end', 'face', 'for', 'form', 'frame', 'galleryimg', 'gutter', 'headers', 'height', 'hidefocus', 'hidden', 'high', 'href', 'hreflang', 'hspace', 'icon', 'id', 'inputmode', 'ismap', 'keytype', 'label', 'leftspacing', 'lang', 'list', 'longdesc', 'loop', 'loopcount', 'loopend', 'loopstart', 'low', 'lowsrc', 'max', 'maxlength', 'media', 'method', 'min', 'multiple', 'name', 'nohref', 'noshade', 'nowrap', 'open', 'optimum', 'pattern', 'ping', 'point-size', 'poster', 'pqg', 'preload', 'prompt', 'radiogroup', 'readonly', 'rel', 'repeat-max', 'repeat-min', 'replace', 'required', 'rev', 'rightspacing', 'rows', 'rowspan', 'rules', 'scope', 'selected', 'shape', 'size', 'span', 'src', 'start', 'step', 'summary', 'suppress', 'tabindex', 'target', 'template', 'title', 'toppadding', 'type', 'unselectable', 'usemap', 'urn', 'valign', 'value', 'variable', 'volume', 'vspace', 'vrml', 'width', 'wrap', 'xml:lang']) unacceptable_elements_with_end_tag = set(['script', 'applet', 'style']) acceptable_css_properties = set(['azimuth', 'background-color', 'border-bottom-color', 'border-collapse', 'border-color', 'border-left-color', 'border-right-color', 'border-top-color', 'clear', 'color', 'cursor', 'direction', 'display', 'elevation', 'float', 'font', 'font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'height', 'letter-spacing', 'line-height', 'overflow', 'pause', 'pause-after', 'pause-before', 'pitch', 'pitch-range', 'richness', 'speak', 'speak-header', 'speak-numeral', 'speak-punctuation', 'speech-rate', 'stress', 'text-align', 'text-decoration', 'text-indent', 'unicode-bidi', 'vertical-align', 'voice-family', 'volume', 'white-space', 'width']) # survey of common keywords found in feeds acceptable_css_keywords = set(['auto', 'aqua', 'black', 'block', 'blue', 'bold', 'both', 'bottom', 'brown', 'center', 'collapse', 'dashed', 'dotted', 'fuchsia', 'gray', 'green', '!important', 'italic', 'left', 'lime', 'maroon', 'medium', 'none', 'navy', 'normal', 'nowrap', 'olive', 'pointer', 'purple', 'red', 'right', 'solid', 'silver', 'teal', 'top', 'transparent', 'underline', 'white', 'yellow']) valid_css_values = re.compile('^(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|' + '\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$') mathml_elements = set(['annotation', 'annotation-xml', 'maction', 'math', 'merror', 'mfenced', 'mfrac', 'mi', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mprescripts', 'mroot', 'mrow', 'mspace', 'msqrt', 'mstyle', 'msub', 'msubsup', 'msup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'none', 'semantics']) mathml_attributes = set(['actiontype', 'align', 'columnalign', 'columnalign', 'columnalign', 'close', 'columnlines', 'columnspacing', 'columnspan', 'depth', 'display', 'displaystyle', 'encoding', 'equalcolumns', 'equalrows', 'fence', 'fontstyle', 'fontweight', 'frame', 'height', 'linethickness', 'lspace', 'mathbackground', 'mathcolor', 'mathvariant', 'mathvariant', 'maxsize', 'minsize', 'open', 'other', 'rowalign', 'rowalign', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'scriptlevel', 'selection', 'separator', 'separators', 'stretchy', 'width', 'width', 'xlink:href', 'xlink:show', 'xlink:type', 'xmlns', 'xmlns:xlink']) # svgtiny - foreignObject + linearGradient + radialGradient + stop svg_elements = set(['a', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle', 'defs', 'desc', 'ellipse', 'foreignObject', 'font-face', 'font-face-name', 'font-face-src', 'g', 'glyph', 'hkern', 'linearGradient', 'line', 'marker', 'metadata', 'missing-glyph', 'mpath', 'path', 'polygon', 'polyline', 'radialGradient', 'rect', 'set', 'stop', 'svg', 'switch', 'text', 'title', 'tspan', 'use']) # svgtiny + class + opacity + offset + xmlns + xmlns:xlink svg_attributes = set(['accent-height', 'accumulate', 'additive', 'alphabetic', 'arabic-form', 'ascent', 'attributeName', 'attributeType', 'baseProfile', 'bbox', 'begin', 'by', 'calcMode', 'cap-height', 'class', 'color', 'color-rendering', 'content', 'cx', 'cy', 'd', 'dx', 'dy', 'descent', 'display', 'dur', 'end', 'fill', 'fill-opacity', 'fill-rule', 'font-family', 'font-size', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'from', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'gradientUnits', 'hanging', 'height', 'horiz-adv-x', 'horiz-origin-x', 'id', 'ideographic', 'k', 'keyPoints', 'keySplines', 'keyTimes', 'lang', 'mathematical', 'marker-end', 'marker-mid', 'marker-start', 'markerHeight', 'markerUnits', 'markerWidth', 'max', 'min', 'name', 'offset', 'opacity', 'orient', 'origin', 'overline-position', 'overline-thickness', 'panose-1', 'path', 'pathLength', 'points', 'preserveAspectRatio', 'r', 'refX', 'refY', 'repeatCount', 'repeatDur', 'requiredExtensions', 'requiredFeatures', 'restart', 'rotate', 'rx', 'ry', 'slope', 'stemh', 'stemv', 'stop-color', 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'target', 'text-anchor', 'to', 'transform', 'type', 'u1', 'u2', 'underline-position', 'underline-thickness', 'unicode', 'unicode-range', 'units-per-em', 'values', 'version', 'viewBox', 'visibility', 'width', 'widths', 'x', 'x-height', 'x1', 'x2', 'xlink:actuate', 'xlink:arcrole', 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type', 'xml:base', 'xml:lang', 'xml:space', 'xmlns', 'xmlns:xlink', 'y', 'y1', 'y2', 'zoomAndPan']) svg_attr_map = None svg_elem_map = None acceptable_svg_properties = set([ 'fill', 'fill-opacity', 'fill-rule', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin', 'stroke-opacity']) def reset(self): _BaseHTMLProcessor.reset(self) self.unacceptablestack = 0 self.mathmlOK = 0 self.svgOK = 0 def unknown_starttag(self, tag, attrs): acceptable_attributes = self.acceptable_attributes keymap = {} if not tag in self.acceptable_elements or self.svgOK: if tag in self.unacceptable_elements_with_end_tag: self.unacceptablestack += 1 # add implicit namespaces to html5 inline svg/mathml if self._type.endswith('html'): if not dict(attrs).get('xmlns'): if tag=='svg': attrs.append( ('xmlns','http://www.w3.org/2000/svg') ) if tag=='math': attrs.append( ('xmlns','http://www.w3.org/1998/Math/MathML') ) # not otherwise acceptable, perhaps it is MathML or SVG? if tag=='math' and ('xmlns','http://www.w3.org/1998/Math/MathML') in attrs: self.mathmlOK += 1 if tag=='svg' and ('xmlns','http://www.w3.org/2000/svg') in attrs: self.svgOK += 1 # chose acceptable attributes based on tag class, else bail if self.mathmlOK and tag in self.mathml_elements: acceptable_attributes = self.mathml_attributes elif self.svgOK and tag in self.svg_elements: # for most vocabularies, lowercasing is a good idea. Many # svg elements, however, are camel case if not self.svg_attr_map: lower=[attr.lower() for attr in self.svg_attributes] mix=[a for a in self.svg_attributes if a not in lower] self.svg_attributes = lower self.svg_attr_map = dict([(a.lower(),a) for a in mix]) lower=[attr.lower() for attr in self.svg_elements] mix=[a for a in self.svg_elements if a not in lower] self.svg_elements = lower self.svg_elem_map = dict([(a.lower(),a) for a in mix]) acceptable_attributes = self.svg_attributes tag = self.svg_elem_map.get(tag,tag) keymap = self.svg_attr_map elif not tag in self.acceptable_elements: return # declare xlink namespace, if needed if self.mathmlOK or self.svgOK: if filter(lambda (n,v): n.startswith('xlink:'),attrs): if not ('xmlns:xlink','http://www.w3.org/1999/xlink') in attrs: attrs.append(('xmlns:xlink','http://www.w3.org/1999/xlink')) clean_attrs = [] for key, value in self.normalize_attrs(attrs): if key in acceptable_attributes: key=keymap.get(key,key) # make sure the uri uses an acceptable uri scheme if key == u'href': value = _makeSafeAbsoluteURI(value) clean_attrs.append((key,value)) elif key=='style': clean_value = self.sanitize_style(value) if clean_value: clean_attrs.append((key,clean_value)) _BaseHTMLProcessor.unknown_starttag(self, tag, clean_attrs) def unknown_endtag(self, tag): if not tag in self.acceptable_elements: if tag in self.unacceptable_elements_with_end_tag: self.unacceptablestack -= 1 if self.mathmlOK and tag in self.mathml_elements: if tag == 'math' and self.mathmlOK: self.mathmlOK -= 1 elif self.svgOK and tag in self.svg_elements: tag = self.svg_elem_map.get(tag,tag) if tag == 'svg' and self.svgOK: self.svgOK -= 1 else: return _BaseHTMLProcessor.unknown_endtag(self, tag) def handle_pi(self, text): pass def handle_decl(self, text): pass def handle_data(self, text): if not self.unacceptablestack: _BaseHTMLProcessor.handle_data(self, text) def sanitize_style(self, style): # disallow urls style=re.compile('url\s*\(\s*[^\s)]+?\s*\)\s*').sub(' ',style) # gauntlet if not re.match("""^([:,;#%.\sa-zA-Z0-9!]|\w-\w|'[\s\w]+'|"[\s\w]+"|\([\d,\s]+\))*$""", style): return '' # This replaced a regexp that used re.match and was prone to pathological back-tracking. if re.sub("\s*[-\w]+\s*:\s*[^:;]*;?", '', style).strip(): return '' clean = [] for prop,value in re.findall("([-\w]+)\s*:\s*([^:;]*)",style): if not value: continue if prop.lower() in self.acceptable_css_properties: clean.append(prop + ': ' + value + ';') elif prop.split('-')[0].lower() in ['background','border','margin','padding']: for keyword in value.split(): if not keyword in self.acceptable_css_keywords and \ not self.valid_css_values.match(keyword): break else: clean.append(prop + ': ' + value + ';') elif self.svgOK and prop.lower() in self.acceptable_svg_properties: clean.append(prop + ': ' + value + ';') return ' '.join(clean) def parse_comment(self, i, report=1): ret = _BaseHTMLProcessor.parse_comment(self, i, report) if ret >= 0: return ret # if ret == -1, this may be a malicious attempt to circumvent # sanitization, or a page-destroying unclosed comment match = re.compile(r'--[^>]*>').search(self.rawdata, i+4) if match: return match.end() # unclosed comment; deliberately fail to handle_data() return len(self.rawdata) def _sanitizeHTML(htmlSource, encoding, _type): if not _SGML_AVAILABLE: return htmlSource p = _HTMLSanitizer(encoding, _type) htmlSource = htmlSource.replace(''): data = data.split('>', 1)[1] if data.count(' stream This function lets you define parsers that take any input source (URL, pathname to local or network file, or actual data as a string) and deal with it in a uniform manner. Returned object is guaranteed to have all the basic stdio read methods (read, readline, readlines). Just .close() the object when you're done with it. If the etag argument is supplied, it will be used as the value of an If-None-Match request header. If the modified argument is supplied, it can be a tuple of 9 integers (as returned by gmtime() in the standard Python time module) or a date string in any format supported by feedparser. Regardless, it MUST be in GMT (Greenwich Mean Time). It will be reformatted into an RFC 1123-compliant date and used as the value of an If-Modified-Since request header. If the agent argument is supplied, it will be used as the value of a User-Agent request header. If the referrer argument is supplied, it will be used as the value of a Referer[sic] request header. If handlers is supplied, it is a list of handlers used to build a urllib2 opener. if request_headers is supplied it is a dictionary of HTTP request headers that will override the values generated by FeedParser. """ if hasattr(url_file_stream_or_string, 'read'): return url_file_stream_or_string if isinstance(url_file_stream_or_string, basestring) \ and urlparse.urlparse(url_file_stream_or_string)[0] in ('http', 'https', 'ftp', 'file', 'feed'): # Deal with the feed URI scheme if url_file_stream_or_string.startswith('feed:http'): url_file_stream_or_string = url_file_stream_or_string[5:] elif url_file_stream_or_string.startswith('feed:'): url_file_stream_or_string = 'http:' + url_file_stream_or_string[5:] if not agent: agent = USER_AGENT # Test for inline user:password credentials for HTTP basic auth auth = None if base64 and not url_file_stream_or_string.startswith('ftp:'): urltype, rest = urllib.splittype(url_file_stream_or_string) realhost, rest = urllib.splithost(rest) if realhost: user_passwd, realhost = urllib.splituser(realhost) if user_passwd: url_file_stream_or_string = '%s://%s%s' % (urltype, realhost, rest) auth = base64.standard_b64encode(user_passwd).strip() # iri support if isinstance(url_file_stream_or_string, unicode): url_file_stream_or_string = _convert_to_idn(url_file_stream_or_string) # try to open with urllib2 (to use optional headers) request = _build_urllib2_request(url_file_stream_or_string, agent, etag, modified, referrer, auth, request_headers) opener = urllib2.build_opener(*tuple(handlers + [_FeedURLHandler()])) opener.addheaders = [] # RMK - must clear so we only send our custom User-Agent try: return opener.open(request) finally: opener.close() # JohnD # try to open with native open function (if url_file_stream_or_string is a filename) try: return open(url_file_stream_or_string, 'rb') except (IOError, UnicodeEncodeError, TypeError): # if url_file_stream_or_string is a unicode object that # cannot be converted to the encoding returned by # sys.getfilesystemencoding(), a UnicodeEncodeError # will be thrown # If url_file_stream_or_string is a string that contains NULL # (such as an XML document encoded in UTF-32), TypeError will # be thrown. pass # treat url_file_stream_or_string as string if isinstance(url_file_stream_or_string, unicode): return _StringIO(url_file_stream_or_string.encode('utf-8')) return _StringIO(url_file_stream_or_string) def _convert_to_idn(url): """Convert a URL to IDN notation""" # this function should only be called with a unicode string # strategy: if the host cannot be encoded in ascii, then # it'll be necessary to encode it in idn form parts = list(urlparse.urlsplit(url)) try: parts[1].encode('ascii') except UnicodeEncodeError: # the url needs to be converted to idn notation host = parts[1].rsplit(':', 1) newhost = [] port = u'' if len(host) == 2: port = host.pop() for h in host[0].split('.'): newhost.append(h.encode('idna').decode('utf-8')) parts[1] = '.'.join(newhost) if port: parts[1] += ':' + port return urlparse.urlunsplit(parts) else: return url def _build_urllib2_request(url, agent, etag, modified, referrer, auth, request_headers): request = urllib2.Request(url) request.add_header('User-Agent', agent) if etag: request.add_header('If-None-Match', etag) if isinstance(modified, basestring): modified = _parse_date(modified) elif isinstance(modified, datetime.datetime): modified = modified.utctimetuple() if modified: # format into an RFC 1123-compliant timestamp. We can't use # time.strftime() since the %a and %b directives can be affected # by the current locale, but RFC 2616 states that dates must be # in English. short_weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] request.add_header('If-Modified-Since', '%s, %02d %s %04d %02d:%02d:%02d GMT' % (short_weekdays[modified[6]], modified[2], months[modified[1] - 1], modified[0], modified[3], modified[4], modified[5])) if referrer: request.add_header('Referer', referrer) if gzip and zlib: request.add_header('Accept-encoding', 'gzip, deflate') elif gzip: request.add_header('Accept-encoding', 'gzip') elif zlib: request.add_header('Accept-encoding', 'deflate') else: request.add_header('Accept-encoding', '') if auth: request.add_header('Authorization', 'Basic %s' % auth) if ACCEPT_HEADER: request.add_header('Accept', ACCEPT_HEADER) # use this for whatever -- cookies, special headers, etc # [('Cookie','Something'),('x-special-header','Another Value')] for header_name, header_value in request_headers.items(): request.add_header(header_name, header_value) request.add_header('A-IM', 'feed') # RFC 3229 support return request _date_handlers = [] def registerDateHandler(func): '''Register a date handler function (takes string, returns 9-tuple date in GMT)''' _date_handlers.insert(0, func) # ISO-8601 date parsing routines written by Fazal Majid. # The ISO 8601 standard is very convoluted and irregular - a full ISO 8601 # parser is beyond the scope of feedparser and would be a worthwhile addition # to the Python library. # A single regular expression cannot parse ISO 8601 date formats into groups # as the standard is highly irregular (for instance is 030104 2003-01-04 or # 0301-04-01), so we use templates instead. # Please note the order in templates is significant because we need a # greedy match. _iso8601_tmpl = ['YYYY-?MM-?DD', 'YYYY-0MM?-?DD', 'YYYY-MM', 'YYYY-?OOO', 'YY-?MM-?DD', 'YY-?OOO', 'YYYY', '-YY-?MM', '-OOO', '-YY', '--MM-?DD', '--MM', '---DD', 'CC', ''] _iso8601_re = [ tmpl.replace( 'YYYY', r'(?P\d{4})').replace( 'YY', r'(?P\d\d)').replace( 'MM', r'(?P[01]\d)').replace( 'DD', r'(?P[0123]\d)').replace( 'OOO', r'(?P[0123]\d\d)').replace( 'CC', r'(?P\d\d$)') + r'(T?(?P\d{2}):(?P\d{2})' + r'(:(?P\d{2}))?' + r'(\.(?P\d+))?' + r'(?P[+-](?P\d{2})(:(?P\d{2}))?|Z)?)?' for tmpl in _iso8601_tmpl] try: del tmpl except NameError: pass _iso8601_matches = [re.compile(regex).match for regex in _iso8601_re] try: del regex except NameError: pass def _parse_date_iso8601(dateString): '''Parse a variety of ISO-8601-compatible formats like 20040105''' m = None for _iso8601_match in _iso8601_matches: m = _iso8601_match(dateString) if m: break if not m: return if m.span() == (0, 0): return params = m.groupdict() ordinal = params.get('ordinal', 0) if ordinal: ordinal = int(ordinal) else: ordinal = 0 year = params.get('year', '--') if not year or year == '--': year = time.gmtime()[0] elif len(year) == 2: # ISO 8601 assumes current century, i.e. 93 -> 2093, NOT 1993 year = 100 * int(time.gmtime()[0] / 100) + int(year) else: year = int(year) month = params.get('month', '-') if not month or month == '-': # ordinals are NOT normalized by mktime, we simulate them # by setting month=1, day=ordinal if ordinal: month = 1 else: month = time.gmtime()[1] month = int(month) day = params.get('day', 0) if not day: # see above if ordinal: day = ordinal elif params.get('century', 0) or \ params.get('year', 0) or params.get('month', 0): day = 1 else: day = time.gmtime()[2] else: day = int(day) # special case of the century - is the first year of the 21st century # 2000 or 2001 ? The debate goes on... if 'century' in params: year = (int(params['century']) - 1) * 100 + 1 # in ISO 8601 most fields are optional for field in ['hour', 'minute', 'second', 'tzhour', 'tzmin']: if not params.get(field, None): params[field] = 0 hour = int(params.get('hour', 0)) minute = int(params.get('minute', 0)) second = int(float(params.get('second', 0))) # weekday is normalized by mktime(), we can ignore it weekday = 0 daylight_savings_flag = -1 tm = [year, month, day, hour, minute, second, weekday, ordinal, daylight_savings_flag] # ISO 8601 time zone adjustments tz = params.get('tz') if tz and tz != 'Z': if tz[0] == '-': tm[3] += int(params.get('tzhour', 0)) tm[4] += int(params.get('tzmin', 0)) elif tz[0] == '+': tm[3] -= int(params.get('tzhour', 0)) tm[4] -= int(params.get('tzmin', 0)) else: return None # Python's time.mktime() is a wrapper around the ANSI C mktime(3c) # which is guaranteed to normalize d/m/y/h/m/s. # Many implementations have bugs, but we'll pretend they don't. return time.localtime(time.mktime(tuple(tm))) registerDateHandler(_parse_date_iso8601) # 8-bit date handling routines written by ytrewq1. _korean_year = u'\ub144' # b3e2 in euc-kr _korean_month = u'\uc6d4' # bff9 in euc-kr _korean_day = u'\uc77c' # c0cf in euc-kr _korean_am = u'\uc624\uc804' # bfc0 c0fc in euc-kr _korean_pm = u'\uc624\ud6c4' # bfc0 c8c4 in euc-kr _korean_onblog_date_re = \ re.compile('(\d{4})%s\s+(\d{2})%s\s+(\d{2})%s\s+(\d{2}):(\d{2}):(\d{2})' % \ (_korean_year, _korean_month, _korean_day)) _korean_nate_date_re = \ re.compile(u'(\d{4})-(\d{2})-(\d{2})\s+(%s|%s)\s+(\d{,2}):(\d{,2}):(\d{,2})' % \ (_korean_am, _korean_pm)) def _parse_date_onblog(dateString): '''Parse a string according to the OnBlog 8-bit date format''' m = _korean_onblog_date_re.match(dateString) if not m: return w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s:%(second)s%(zonediff)s' % \ {'year': m.group(1), 'month': m.group(2), 'day': m.group(3),\ 'hour': m.group(4), 'minute': m.group(5), 'second': m.group(6),\ 'zonediff': '+09:00'} return _parse_date_w3dtf(w3dtfdate) registerDateHandler(_parse_date_onblog) def _parse_date_nate(dateString): '''Parse a string according to the Nate 8-bit date format''' m = _korean_nate_date_re.match(dateString) if not m: return hour = int(m.group(5)) ampm = m.group(4) if (ampm == _korean_pm): hour += 12 hour = str(hour) if len(hour) == 1: hour = '0' + hour w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s:%(second)s%(zonediff)s' % \ {'year': m.group(1), 'month': m.group(2), 'day': m.group(3),\ 'hour': hour, 'minute': m.group(6), 'second': m.group(7),\ 'zonediff': '+09:00'} return _parse_date_w3dtf(w3dtfdate) registerDateHandler(_parse_date_nate) # Unicode strings for Greek date strings _greek_months = \ { \ u'\u0399\u03b1\u03bd': u'Jan', # c9e1ed in iso-8859-7 u'\u03a6\u03b5\u03b2': u'Feb', # d6e5e2 in iso-8859-7 u'\u039c\u03ac\u03ce': u'Mar', # ccdcfe in iso-8859-7 u'\u039c\u03b1\u03ce': u'Mar', # cce1fe in iso-8859-7 u'\u0391\u03c0\u03c1': u'Apr', # c1f0f1 in iso-8859-7 u'\u039c\u03ac\u03b9': u'May', # ccdce9 in iso-8859-7 u'\u039c\u03b1\u03ca': u'May', # cce1fa in iso-8859-7 u'\u039c\u03b1\u03b9': u'May', # cce1e9 in iso-8859-7 u'\u0399\u03bf\u03cd\u03bd': u'Jun', # c9effded in iso-8859-7 u'\u0399\u03bf\u03bd': u'Jun', # c9efed in iso-8859-7 u'\u0399\u03bf\u03cd\u03bb': u'Jul', # c9effdeb in iso-8859-7 u'\u0399\u03bf\u03bb': u'Jul', # c9f9eb in iso-8859-7 u'\u0391\u03cd\u03b3': u'Aug', # c1fde3 in iso-8859-7 u'\u0391\u03c5\u03b3': u'Aug', # c1f5e3 in iso-8859-7 u'\u03a3\u03b5\u03c0': u'Sep', # d3e5f0 in iso-8859-7 u'\u039f\u03ba\u03c4': u'Oct', # cfeaf4 in iso-8859-7 u'\u039d\u03bf\u03ad': u'Nov', # cdefdd in iso-8859-7 u'\u039d\u03bf\u03b5': u'Nov', # cdefe5 in iso-8859-7 u'\u0394\u03b5\u03ba': u'Dec', # c4e5ea in iso-8859-7 } _greek_wdays = \ { \ u'\u039a\u03c5\u03c1': u'Sun', # caf5f1 in iso-8859-7 u'\u0394\u03b5\u03c5': u'Mon', # c4e5f5 in iso-8859-7 u'\u03a4\u03c1\u03b9': u'Tue', # d4f1e9 in iso-8859-7 u'\u03a4\u03b5\u03c4': u'Wed', # d4e5f4 in iso-8859-7 u'\u03a0\u03b5\u03bc': u'Thu', # d0e5ec in iso-8859-7 u'\u03a0\u03b1\u03c1': u'Fri', # d0e1f1 in iso-8859-7 u'\u03a3\u03b1\u03b2': u'Sat', # d3e1e2 in iso-8859-7 } _greek_date_format_re = \ re.compile(u'([^,]+),\s+(\d{2})\s+([^\s]+)\s+(\d{4})\s+(\d{2}):(\d{2}):(\d{2})\s+([^\s]+)') def _parse_date_greek(dateString): '''Parse a string according to a Greek 8-bit date format.''' m = _greek_date_format_re.match(dateString) if not m: return wday = _greek_wdays[m.group(1)] month = _greek_months[m.group(3)] rfc822date = '%(wday)s, %(day)s %(month)s %(year)s %(hour)s:%(minute)s:%(second)s %(zonediff)s' % \ {'wday': wday, 'day': m.group(2), 'month': month, 'year': m.group(4),\ 'hour': m.group(5), 'minute': m.group(6), 'second': m.group(7),\ 'zonediff': m.group(8)} return _parse_date_rfc822(rfc822date) registerDateHandler(_parse_date_greek) # Unicode strings for Hungarian date strings _hungarian_months = \ { \ u'janu\u00e1r': u'01', # e1 in iso-8859-2 u'febru\u00e1ri': u'02', # e1 in iso-8859-2 u'm\u00e1rcius': u'03', # e1 in iso-8859-2 u'\u00e1prilis': u'04', # e1 in iso-8859-2 u'm\u00e1ujus': u'05', # e1 in iso-8859-2 u'j\u00fanius': u'06', # fa in iso-8859-2 u'j\u00falius': u'07', # fa in iso-8859-2 u'augusztus': u'08', u'szeptember': u'09', u'okt\u00f3ber': u'10', # f3 in iso-8859-2 u'november': u'11', u'december': u'12', } _hungarian_date_format_re = \ re.compile(u'(\d{4})-([^-]+)-(\d{,2})T(\d{,2}):(\d{2})((\+|-)(\d{,2}:\d{2}))') def _parse_date_hungarian(dateString): '''Parse a string according to a Hungarian 8-bit date format.''' m = _hungarian_date_format_re.match(dateString) if not m or m.group(2) not in _hungarian_months: return None month = _hungarian_months[m.group(2)] day = m.group(3) if len(day) == 1: day = '0' + day hour = m.group(4) if len(hour) == 1: hour = '0' + hour w3dtfdate = '%(year)s-%(month)s-%(day)sT%(hour)s:%(minute)s%(zonediff)s' % \ {'year': m.group(1), 'month': month, 'day': day,\ 'hour': hour, 'minute': m.group(5),\ 'zonediff': m.group(6)} return _parse_date_w3dtf(w3dtfdate) registerDateHandler(_parse_date_hungarian) # W3DTF-style date parsing adapted from PyXML xml.utils.iso8601, written by # Drake and licensed under the Python license. Removed all range checking # for month, day, hour, minute, and second, since mktime will normalize # these later # Modified to also support MSSQL-style datetimes as defined at: # http://msdn.microsoft.com/en-us/library/ms186724.aspx # (which basically means allowing a space as a date/time/timezone separator) def _parse_date_w3dtf(dateString): def __extract_date(m): year = int(m.group('year')) if year < 100: year = 100 * int(time.gmtime()[0] / 100) + int(year) if year < 1000: return 0, 0, 0 julian = m.group('julian') if julian: julian = int(julian) month = julian / 30 + 1 day = julian % 30 + 1 jday = None while jday != julian: t = time.mktime((year, month, day, 0, 0, 0, 0, 0, 0)) jday = time.gmtime(t)[-2] diff = abs(jday - julian) if jday > julian: if diff < day: day = day - diff else: month = month - 1 day = 31 elif jday < julian: if day + diff < 28: day = day + diff else: month = month + 1 return year, month, day month = m.group('month') day = 1 if month is None: month = 1 else: month = int(month) day = m.group('day') if day: day = int(day) else: day = 1 return year, month, day def __extract_time(m): if not m: return 0, 0, 0 hours = m.group('hours') if not hours: return 0, 0, 0 hours = int(hours) minutes = int(m.group('minutes')) seconds = m.group('seconds') if seconds: seconds = int(seconds) else: seconds = 0 return hours, minutes, seconds def __extract_tzd(m): '''Return the Time Zone Designator as an offset in seconds from UTC.''' if not m: return 0 tzd = m.group('tzd') if not tzd: return 0 if tzd == 'Z': return 0 hours = int(m.group('tzdhours')) minutes = m.group('tzdminutes') if minutes: minutes = int(minutes) else: minutes = 0 offset = (hours*60 + minutes) * 60 if tzd[0] == '+': return -offset return offset __date_re = ('(?P\d\d\d\d)' '(?:(?P-|)' '(?:(?P\d\d)(?:(?P=dsep)(?P\d\d))?' '|(?P\d\d\d)))?') __tzd_re = ' ?(?P[-+](?P\d\d)(?::?(?P\d\d))|Z)?' __time_re = ('(?P\d\d)(?P:|)(?P\d\d)' '(?:(?P=tsep)(?P\d\d)(?:[.,]\d+)?)?' + __tzd_re) __datetime_re = '%s(?:[T ]%s)?' % (__date_re, __time_re) __datetime_rx = re.compile(__datetime_re) m = __datetime_rx.match(dateString) if (m is None) or (m.group() != dateString): return gmt = __extract_date(m) + __extract_time(m) + (0, 0, 0) if gmt[0] == 0: return return time.gmtime(time.mktime(gmt) + __extract_tzd(m) - time.timezone) registerDateHandler(_parse_date_w3dtf) # Define the strings used by the RFC822 datetime parser _rfc822_months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'] _rfc822_daynames = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] # Only the first three letters of the month name matter _rfc822_month = "(?P%s)(?:[a-z]*,?)" % ('|'.join(_rfc822_months)) # The year may be 2 or 4 digits; capture the century if it exists _rfc822_year = "(?P(?:\d{2})?\d{2})" _rfc822_day = "(?P *\d{1,2})" _rfc822_date = "%s %s %s" % (_rfc822_day, _rfc822_month, _rfc822_year) _rfc822_hour = "(?P\d{2}):(?P\d{2})(?::(?P\d{2}))?" _rfc822_tz = "(?Put|gmt(?:[+-]\d{2}:\d{2})?|[aecmp][sd]?t|[zamny]|[+-]\d{4})" _rfc822_tznames = { 'ut': 0, 'gmt': 0, 'z': 0, 'adt': -3, 'ast': -4, 'at': -4, 'edt': -4, 'est': -5, 'et': -5, 'cdt': -5, 'cst': -6, 'ct': -6, 'mdt': -6, 'mst': -7, 'mt': -7, 'pdt': -7, 'pst': -8, 'pt': -8, 'a': -1, 'n': 1, 'm': -12, 'y': 12, } # The timezone may be prefixed by 'Etc/' _rfc822_time = "%s (?:etc/)?%s" % (_rfc822_hour, _rfc822_tz) _rfc822_dayname = "(?P%s)" % ('|'.join(_rfc822_daynames)) _rfc822_match = re.compile( "(?:%s, )?%s(?: %s)?" % (_rfc822_dayname, _rfc822_date, _rfc822_time) ).match def _parse_date_group_rfc822(m): # Calculate a date and timestamp for k in ('year', 'day', 'hour', 'minute', 'second'): m[k] = int(m[k]) m['month'] = _rfc822_months.index(m['month']) + 1 # If the year is 2 digits, assume everything in the 90's is the 1990's if m['year'] < 100: m['year'] += (1900, 2000)[m['year'] < 90] stamp = datetime.datetime(*[m[i] for i in ('year', 'month', 'day', 'hour', 'minute', 'second')]) # Use the timezone information to calculate the difference between # the given date and timestamp and Universal Coordinated Time tzhour = 0 tzmin = 0 if m['tz'] and m['tz'].startswith('gmt'): # Handle GMT and GMT+hh:mm timezone syntax (the trailing # timezone info will be handled by the next `if` block) m['tz'] = ''.join(m['tz'][3:].split(':')) or 'gmt' if not m['tz']: pass elif m['tz'].startswith('+'): tzhour = int(m['tz'][1:3]) tzmin = int(m['tz'][3:]) elif m['tz'].startswith('-'): tzhour = int(m['tz'][1:3]) * -1 tzmin = int(m['tz'][3:]) * -1 else: tzhour = _rfc822_tznames[m['tz']] delta = datetime.timedelta(0, 0, 0, 0, tzmin, tzhour) # Return the date and timestamp in UTC return (stamp - delta).utctimetuple() def _parse_date_rfc822(dt): """Parse RFC 822 dates and times, with one minor difference: years may be 4DIGIT or 2DIGIT. http://tools.ietf.org/html/rfc822#section-5""" try: m = _rfc822_match(dt.lower()).groupdict(0) except AttributeError: return None return _parse_date_group_rfc822(m) registerDateHandler(_parse_date_rfc822) def _parse_date_rfc822_grubby(dt): """Parse date format similar to RFC 822, but the comma after the dayname is optional and month/day are inverted""" _rfc822_date_grubby = "%s %s %s" % (_rfc822_month, _rfc822_day, _rfc822_year) _rfc822_match_grubby = re.compile( "(?:%s[,]? )?%s(?: %s)?" % (_rfc822_dayname, _rfc822_date_grubby, _rfc822_time) ).match try: m = _rfc822_match_grubby(dt.lower()).groupdict(0) except AttributeError: return None return _parse_date_group_rfc822(m) registerDateHandler(_parse_date_rfc822_grubby) def _parse_date_asctime(dt): """Parse asctime-style dates""" dayname, month, day, remainder = dt.split(None, 3) # Convert month and day into zero-padded integers month = '%02i ' % (_rfc822_months.index(month.lower()) + 1) day = '%02i ' % (int(day),) dt = month + day + remainder return time.strptime(dt, '%m %d %H:%M:%S %Y')[:-1] + (0, ) registerDateHandler(_parse_date_asctime) def _parse_date_perforce(aDateString): """parse a date in yyyy/mm/dd hh:mm:ss TTT format""" # Fri, 2006/09/15 08:19:53 EDT _my_date_pattern = re.compile( \ r'(\w{,3}), (\d{,4})/(\d{,2})/(\d{2}) (\d{,2}):(\d{2}):(\d{2}) (\w{,3})') m = _my_date_pattern.search(aDateString) if m is None: return None dow, year, month, day, hour, minute, second, tz = m.groups() months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] dateString = "%s, %s %s %s %s:%s:%s %s" % (dow, day, months[int(month) - 1], year, hour, minute, second, tz) tm = rfc822.parsedate_tz(dateString) if tm: return time.gmtime(rfc822.mktime_tz(tm)) registerDateHandler(_parse_date_perforce) def _parse_date(dateString): '''Parses a variety of date formats into a 9-tuple in GMT''' if not dateString: return None for handler in _date_handlers: try: date9tuple = handler(dateString) except (KeyError, OverflowError, ValueError): continue if not date9tuple: continue if len(date9tuple) != 9: continue return date9tuple return None # Each marker represents some of the characters of the opening XML # processing instruction (' RE_XML_DECLARATION = re.compile('^<\?xml[^>]*?>') # Capture the value of the XML processing instruction's encoding attribute. # Example: RE_XML_PI_ENCODING = re.compile(_s2bytes('^<\?.*encoding=[\'"](.*?)[\'"].*\?>')) def convert_to_utf8(http_headers, data): '''Detect and convert the character encoding to UTF-8. http_headers is a dictionary data is a raw string (not Unicode)''' # This is so much trickier than it sounds, it's not even funny. # According to RFC 3023 ('XML Media Types'), if the HTTP Content-Type # is application/xml, application/*+xml, # application/xml-external-parsed-entity, or application/xml-dtd, # the encoding given in the charset parameter of the HTTP Content-Type # takes precedence over the encoding given in the XML prefix within the # document, and defaults to 'utf-8' if neither are specified. But, if # the HTTP Content-Type is text/xml, text/*+xml, or # text/xml-external-parsed-entity, the encoding given in the XML prefix # within the document is ALWAYS IGNORED and only the encoding given in # the charset parameter of the HTTP Content-Type header should be # respected, and it defaults to 'us-ascii' if not specified. # Furthermore, discussion on the atom-syntax mailing list with the # author of RFC 3023 leads me to the conclusion that any document # served with a Content-Type of text/* and no charset parameter # must be treated as us-ascii. (We now do this.) And also that it # must always be flagged as non-well-formed. (We now do this too.) # If Content-Type is unspecified (input was local file or non-HTTP source) # or unrecognized (server just got it totally wrong), then go by the # encoding given in the XML prefix of the document and default to # 'iso-8859-1' as per the HTTP specification (RFC 2616). # Then, assuming we didn't find a character encoding in the HTTP headers # (and the HTTP Content-type allowed us to look in the body), we need # to sniff the first few bytes of the XML data and try to determine # whether the encoding is ASCII-compatible. Section F of the XML # specification shows the way here: # http://www.w3.org/TR/REC-xml/#sec-guessing-no-ext-info # If the sniffed encoding is not ASCII-compatible, we need to make it # ASCII compatible so that we can sniff further into the XML declaration # to find the encoding attribute, which will tell us the true encoding. # Of course, none of this guarantees that we will be able to parse the # feed in the declared character encoding (assuming it was declared # correctly, which many are not). iconv_codec can help a lot; # you should definitely install it if you can. # http://cjkpython.i18n.org/ bom_encoding = u'' xml_encoding = u'' rfc3023_encoding = u'' # Look at the first few bytes of the document to guess what # its encoding may be. We only need to decode enough of the # document that we can use an ASCII-compatible regular # expression to search for an XML encoding declaration. # The heuristic follows the XML specification, section F: # http://www.w3.org/TR/REC-xml/#sec-guessing-no-ext-info # Check for BOMs first. if data[:4] == codecs.BOM_UTF32_BE: bom_encoding = u'utf-32be' data = data[4:] elif data[:4] == codecs.BOM_UTF32_LE: bom_encoding = u'utf-32le' data = data[4:] elif data[:2] == codecs.BOM_UTF16_BE and data[2:4] != ZERO_BYTES: bom_encoding = u'utf-16be' data = data[2:] elif data[:2] == codecs.BOM_UTF16_LE and data[2:4] != ZERO_BYTES: bom_encoding = u'utf-16le' data = data[2:] elif data[:3] == codecs.BOM_UTF8: bom_encoding = u'utf-8' data = data[3:] # Check for the characters '''' if RE_XML_DECLARATION.search(data): data = RE_XML_DECLARATION.sub(new_declaration, data) else: data = new_declaration + u'\n' + data data = data.encode('utf-8') break # if still no luck, give up if not known_encoding: error = CharacterEncodingUnknown( 'document encoding unknown, I tried ' + '%s, %s, utf-8, windows-1252, and iso-8859-2 but nothing worked' % (rfc3023_encoding, xml_encoding)) rfc3023_encoding = u'' elif proposed_encoding != rfc3023_encoding: error = CharacterEncodingOverride( 'document declared as %s, but parsed as %s' % (rfc3023_encoding, proposed_encoding)) rfc3023_encoding = proposed_encoding return data, rfc3023_encoding, error # Match XML entity declarations. # Example: RE_ENTITY_PATTERN = re.compile(_s2bytes(r'^\s*]*?)>'), re.MULTILINE) # Match XML DOCTYPE declarations. # Example: RE_DOCTYPE_PATTERN = re.compile(_s2bytes(r'^\s*]*?)>'), re.MULTILINE) # Match safe entity declarations. # This will allow hexadecimal character references through, # as well as text, but not arbitrary nested entities. # Example: cubed "³" # Example: copyright "(C)" # Forbidden: explode1 "&explode2;&explode2;" RE_SAFE_ENTITY_PATTERN = re.compile(_s2bytes('\s+(\w+)\s+"(&#\w+;|[^&"]*)"')) def replace_doctype(data): '''Strips and replaces the DOCTYPE, returns (rss_version, stripped_data) rss_version may be 'rss091n' or None stripped_data is the same XML document with a replaced DOCTYPE ''' # Divide the document into two groups by finding the location # of the first element that doesn't begin with '\n\n]>') data = RE_DOCTYPE_PATTERN.sub(replacement, head) + data # Precompute the safe entities for the loose parser. safe_entities = dict((k.decode('utf-8'), v.decode('utf-8')) for k, v in RE_SAFE_ENTITY_PATTERN.findall(replacement)) return version, data, safe_entities def parse(url_file_stream_or_string, etag=None, modified=None, agent=None, referrer=None, handlers=None, request_headers=None, response_headers=None): '''Parse a feed from a URL, file, stream, or string. request_headers, if given, is a dict from http header name to value to add to the request; this overrides internally generated values. ''' if handlers is None: handlers = [] if request_headers is None: request_headers = {} if response_headers is None: response_headers = {} result = FeedParserDict() result['feed'] = FeedParserDict() result['entries'] = [] result['bozo'] = 0 if not isinstance(handlers, list): handlers = [handlers] try: f = _open_resource(url_file_stream_or_string, etag, modified, agent, referrer, handlers, request_headers) data = f.read() except Exception, e: result['bozo'] = 1 result['bozo_exception'] = e data = None f = None if hasattr(f, 'headers'): result['headers'] = dict(f.headers) # overwrite existing headers using response_headers if 'headers' in result: result['headers'].update(response_headers) elif response_headers: result['headers'] = copy.deepcopy(response_headers) # lowercase all of the HTTP headers for comparisons per RFC 2616 if 'headers' in result: http_headers = dict((k.lower(), v) for k, v in result['headers'].items()) else: http_headers = {} # if feed is gzip-compressed, decompress it if f and data and http_headers: if gzip and 'gzip' in http_headers.get('content-encoding', ''): try: data = gzip.GzipFile(fileobj=_StringIO(data)).read() except (IOError, struct.error), e: # IOError can occur if the gzip header is bad. # struct.error can occur if the data is damaged. result['bozo'] = 1 result['bozo_exception'] = e if isinstance(e, struct.error): # A gzip header was found but the data is corrupt. # Ideally, we should re-request the feed without the # 'Accept-encoding: gzip' header, but we don't. data = None elif zlib and 'deflate' in http_headers.get('content-encoding', ''): try: data = zlib.decompress(data) except zlib.error, e: try: # The data may have no headers and no checksum. data = zlib.decompress(data, -15) except zlib.error, e: result['bozo'] = 1 result['bozo_exception'] = e # save HTTP headers if http_headers: if 'etag' in http_headers: etag = http_headers.get('etag', u'') if not isinstance(etag, unicode): etag = etag.decode('utf-8', 'ignore') if etag: result['etag'] = etag if 'last-modified' in http_headers: modified = http_headers.get('last-modified', u'') if modified: result['modified'] = modified result['modified_parsed'] = _parse_date(modified) if hasattr(f, 'url'): if not isinstance(f.url, unicode): result['href'] = f.url.decode('utf-8', 'ignore') else: result['href'] = f.url result['status'] = 200 if hasattr(f, 'status'): result['status'] = f.status if hasattr(f, 'close'): f.close() if data is None: return result # Stop processing if the server sent HTTP 304 Not Modified. if getattr(f, 'code', 0) == 304: result['version'] = u'' result['debug_message'] = 'The feed has not changed since you last checked, ' + \ 'so the server sent no data. This is a feature, not a bug!' return result data, result['encoding'], error = convert_to_utf8(http_headers, data) use_strict_parser = result['encoding'] and True or False if error is not None: result['bozo'] = 1 result['bozo_exception'] = error result['version'], data, entities = replace_doctype(data) # Ensure that baseuri is an absolute URI using an acceptable URI scheme. contentloc = http_headers.get('content-location', u'') href = result.get('href', u'') baseuri = _makeSafeAbsoluteURI(href, contentloc) or _makeSafeAbsoluteURI(contentloc) or href baselang = http_headers.get('content-language', None) if not isinstance(baselang, unicode) and baselang is not None: baselang = baselang.decode('utf-8', 'ignore') if not _XML_AVAILABLE: use_strict_parser = 0 if use_strict_parser: # initialize the SAX parser feedparser = _StrictFeedParser(baseuri, baselang, 'utf-8') saxparser = xml.sax.make_parser(PREFERRED_XML_PARSERS) saxparser.setFeature(xml.sax.handler.feature_namespaces, 1) try: # disable downloading external doctype references, if possible saxparser.setFeature(xml.sax.handler.feature_external_ges, 0) except xml.sax.SAXNotSupportedException: pass saxparser.setContentHandler(feedparser) saxparser.setErrorHandler(feedparser) source = xml.sax.xmlreader.InputSource() source.setByteStream(_StringIO(data)) try: saxparser.parse(source) except xml.sax.SAXException, e: result['bozo'] = 1 result['bozo_exception'] = feedparser.exc or e use_strict_parser = 0 if not use_strict_parser and _SGML_AVAILABLE: feedparser = _LooseFeedParser(baseuri, baselang, 'utf-8', entities) feedparser.feed(data.decode('utf-8', 'replace')) result['feed'] = feedparser.feeddata result['entries'] = feedparser.entries result['version'] = result['version'] or feedparser.version result['namespaces'] = feedparser.namespacesInUse return result SABnzbd-2.3.2/sabnzbd/utils/getperformance.py0000644000000000000000000000351113217005257017267 0ustar 00000000000000import platform, subprocess def getcpu(): # find the CPU name (which needs a different method per OS), and return it # If none found, return platform.platform(). cputype = None try: if platform.system() == "Windows": import _winreg as winreg # needed on Python 2 key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"Hardware\Description\System\CentralProcessor\0") cputype = winreg.QueryValueEx(key, "ProcessorNameString")[0] winreg.CloseKey(key) elif platform.system() == "Darwin": cputype = subprocess.check_output(['sysctl', "-n", "machdep.cpu.brand_string"]).strip() elif platform.system() == "Linux": for myline in open("/proc/cpuinfo"): if myline.startswith(('model name')): # Typical line: # model name : Intel(R) Xeon(R) CPU E5335 @ 2.00GHz cputype = myline.split(":", 1)[1] # get everything after the first ":" break # we're done except: # An exception, maybe due to a subprocess call gone wrong pass if cputype: # OK, found. Remove unnneeded spaces: cputype = " ".join(cputype.split()) else: # Not found, so let's fall back to platform() cputype = platform.platform() return cputype def getpystone(): value = None for pystonemodule in ['test.pystone', 'pystone']: try: exec "from " + pystonemodule + " import pystones" value = int(pystones(1000)[1]) break # import and calculation worked, so we're done. Get out of the for loop except: pass # ... the import went wrong, so continue in the for loop return value if __name__ == '__main__': print getpystone() print getcpu() SABnzbd-2.3.2/sabnzbd/utils/happyeyeballs.py0000644000000000000000000001530113217005257017130 0ustar 00000000000000#!/usr/bin/env python # Python implementation of RFC 6555 / Happy Eyeballs: find the quickest IPv4/IPv6 connection # See https://tools.ietf.org/html/rfc6555 # Method: Start parallel sessions using threads, and only wait for the quickest succesful socket connect # If the HOST has an IPv6 address, IPv6 is given a head start by delaying IPv4. See https://tools.ietf.org/html/rfc6555#section-4.1 # You can run this as a standalone program, or as a module: ''' from happyeyeballs import happyeyeballs print happyeyeballs('newszilla.xs4all.nl', port=119) ''' # or with more logging: ''' from happyeyeballs import happyeyeballs import logging logger = logging.getLogger('') logger.setLevel(logging.DEBUG) print happyeyeballs('newszilla.xs4all.nl', port=119) ''' import socket import ssl import Queue import threading import time import logging DEBUG = False # called by each thread def do_socket_connect(queue, ip, PORT, SSL, ipv4delay): # connect to the ip, and put the result into the queue if DEBUG: logging.debug("Input for thread is %s %s %s", ip, PORT, SSL) try: # CREATE SOCKET if ip.find(':') >= 0: s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) if ip.find('.') >= 0: time.sleep(ipv4delay) # IPv4 ... so a delay for IPv4 as we prefer IPv6. Note: ipv4delay could be 0 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(3) if not SSL: # Connect ... s.connect((ip, PORT)) # ... and close s.close() else: # WRAP SOCKET wrappedSocket = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1) # CONNECT wrappedSocket.connect((ip, PORT)) # CLOSE SOCKET CONNECTION wrappedSocket.close() queue.put((ip, True)) if DEBUG: logging.debug("connect to %s OK", ip) except: queue.put((ip, False)) if DEBUG: logging.debug("connect to %s not OK", ip) pass def happyeyeballs(HOST, **kwargs): # Happyeyeballs function, with caching of the results # Fill out the parameters into the variables try: PORT = kwargs['port'] except: PORT = 80 try: SSL = kwargs['ssl'] except: SSL = False try: preferipv6 = kwargs['preferipv6'] except: preferipv6 = True # prefer IPv6, so give IPv6 connects a head start by delaying IPv4 # Find out if a cached result is available, and recent enough: timecurrent = int(time.time()) # current time in seconds since epoch retentionseconds = 100 hostkey = (HOST, PORT, SSL, preferipv6) # Example key: (u'ssl.astraweb.com', 563, True, True) try: happyeyeballs.happylist[hostkey] # just to check: does it exist? # No exception, so entry exists, so let's check the time: timecached = happyeyeballs.happylist[hostkey][1] if timecurrent - timecached <= retentionseconds: if DEBUG: logging.debug("existing cached result recent enough") return happyeyeballs.happylist[hostkey][0] else: if DEBUG: logging.debug("existing cached result too old. Find a new one") # Continue a few lines down except: # Exception, so entry not there, so we have to fill it out if DEBUG: logging.debug("Host not yet in the cache. Find entry") pass # we only arrive here if the entry has to be determined. So let's do that: # We have to determine the (new) best IP address start = time.clock() if DEBUG: logging.debug("\n\n%s %s %s %s", HOST, PORT, SSL, preferipv6) ipv4delay = 0 try: # Check if there is an AAAA / IPv6 result for this host: info = socket.getaddrinfo(HOST, PORT, socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_IP, socket.AI_CANONNAME) if DEBUG: logging.debug("IPv6 address found for %s", HOST) if preferipv6: ipv4delay=0.1 # preferipv6, AND at least one IPv6 found, so give IPv4 (!) a delay so that IPv6 has a head start and is preferred except: if DEBUG: logging.debug("No IPv6 address found for %s", HOST) myqueue = Queue.Queue() # queue used for threads giving back the results try: # Get all IP (IPv4 and IPv6) addresses: allinfo = socket.getaddrinfo(HOST, PORT, 0, 0, socket.IPPROTO_TCP) for info in allinfo: address = info[4][0] thisthread = threading.Thread(target=do_socket_connect, args=(myqueue, address, PORT, SSL, ipv4delay)) thisthread.daemon = True thisthread.start() result = None # default return value, used if none of threads says True/"OK", so no connect on any IP address # start reading from the Queue for message from the threads: for i in range(len(allinfo)): s = myqueue.get() # get a response if s[1] == True: result = s[0] break # the first True/"OK" is enough, so break out of for loop except: if DEBUG: logging.debug("something went wrong in the try block") result = None logging.info("Quickest IP address for %s (port %s, ssl %s, preferipv6 %s) is %s", HOST, PORT, SSL, preferipv6, result) delay = int(1000 * (time.clock() - start)) logging.debug("Happy Eyeballs lookup and port connect took %s ms", delay) # We're done. Store and return the result if result: happyeyeballs.happylist[hostkey] = ( result, timecurrent ) if DEBUG: logging.debug("Determined new result for %s with result %s", (hostkey, happyeyeballs.happylist[hostkey]) ) return result happyeyeballs.happylist = {} # The cached results. This static variable must be after the def happyeyeballs() if __name__ == '__main__': logger = logging.getLogger('') logger.setLevel(logging.INFO) if DEBUG: logger.setLevel(logging.DEBUG) # plain HTTP/HTTPS sites: print happyeyeballs('www.google.com') print happyeyeballs('www.google.com', port=443, ssl=True) print happyeyeballs('www.nu.nl') # newsservers: print happyeyeballs('newszilla6.xs4all.nl', port=119) print happyeyeballs('newszilla.xs4all.nl', port=119) print happyeyeballs('block.cheapnews.eu', port=119) print happyeyeballs('block.cheapnews.eu', port=443, ssl=True) print happyeyeballs('sslreader.eweka.nl', port=563, ssl=True) print happyeyeballs('news.thundernews.com', port=119) print happyeyeballs('news.thundernews.com', port=119, preferipv6=False) print happyeyeballs('secure.eu.thundernews.com', port=563, ssl=True) # Strange cases print happyeyeballs('does.not.resolve', port=443, ssl=True) print happyeyeballs('www.google.com', port=119) print happyeyeballs('216.58.211.164') SABnzbd-2.3.2/sabnzbd/utils/json.py0000644000000000000000000000720213217005257015240 0ustar 00000000000000import string import types import logging ## json.py implements a JSON (http://json.org) reader and writer. ## Copyright (C) 2005 Patrick D. Logan ## Contact mailto:patrickdlogan@stardecisions.com ## ## This library is free software; you can redistribute it and/or ## modify it under the terms of the GNU Lesser General Public ## License as published by the Free Software Foundation; either ## version 2.1 of the License, or (at your option) any later version. ## ## This library is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## Lesser General Public License for more details. ## ## You should have received a copy of the GNU Lesser General Public ## License along with this library; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Remark by ShyPike: removed the decoding of JSON, ## because it's not used by SABnzbd ## The full source package can be obtained from: ## http://sourceforge.net/projects/json-py # Log first 10 encounters of LATIN-1 strings LATIN_COUNTER = 10 class WriteException(Exception): pass class JsonWriter(object): def _append(self, s): self._results.append(s) def write(self, obj, escaped_forward_slash=False): self._escaped_forward_slash = escaped_forward_slash self._results = [] self._write(obj) return "".join(self._results) def _write(self, obj): global LATIN_COUNTER ty = type(obj) if ty is types.DictType: n = len(obj) self._append("{") for k, v in obj.items(): self._write(k) self._append(":") self._write(v) n = n - 1 if n > 0: self._append(",") self._append("}") elif ty is types.ListType or ty is types.TupleType: n = len(obj) self._append("[") for item in obj: self._write(item) n = n - 1 if n > 0: self._append(",") self._append("]") elif ty is types.StringType or ty is types.UnicodeType: self._append('"') if ty is types.UnicodeType: obj = obj.encode('utf-8', 'replace') else: try: obj.decode('utf-8') except: obj = obj.decode('latin-1').encode('utf-8', 'replace') if LATIN_COUNTER: logging.info('JSON encoder sees Latin-1: %s', obj) LATIN_COUNTER -= 1 obj = obj.replace('\\', r'\\') if self._escaped_forward_slash: obj = obj.replace('/', r'\/') obj = obj.replace('"', r'\"') obj = obj.replace('\b', r'\b') obj = obj.replace('\f', r'\f') obj = obj.replace('\n', r'\n') obj = obj.replace('\r', r'\r') obj = obj.replace('\t', r'\t') self._append(obj) self._append('"') elif ty is types.IntType or ty is types.LongType: self._append(str(obj)) elif ty is types.FloatType: self._append("%f" % obj) elif obj is True: self._append("true") elif obj is False: self._append("false") elif obj is None: self._append("null") else: raise WriteException, "Cannot write in JSON: %s" % repr(obj) SABnzbd-2.3.2/sabnzbd/utils/kronos.py0000644000000000000000000004621613217005257015612 0ustar 00000000000000#!/usr/bin/python """Module that provides a cron-like task scheduler. This task scheduler is designed to be used from inside your own program. You can schedule Python functions to be called at specific intervals or days. It uses the standard 'sched' module for the actual task scheduling, but provides much more: * repeated tasks (at intervals, or on specific days) * error handling (exceptions in tasks don't kill the scheduler) * optional to run scheduler in its own thread or separate process * optional to run a task in its own thread or separate process If the threading module is available, you can use the various Threaded variants of the scheduler and associated tasks. If threading is not available, you could still use the forked variants. If fork is also not available, all processing is done in a single process, sequentially. There are three Scheduler classes: Scheduler ThreadedScheduler ForkedScheduler You usually add new tasks to a scheduler using the add_interval_task or add_daytime_task methods, with the appropriate processmethod argument to select sequential, threaded or forked processing. NOTE: it is impossible to add new tasks to a ForkedScheduler, after the scheduler has been started! For more control you can use one of the following Task classes and use schedule_task or schedule_task_abs: IntervalTask ThreadedIntervalTask ForkedIntervalTask SingleTask ThreadedSingleTask ForkedSingleTask WeekdayTask ThreadedWeekdayTask ForkedWeekdayTask MonthdayTask ThreadedMonthdayTask ForkedMonthdayTask Kronos is the Greek God of Time. Kronos scheduler (c) Irmen de Jong. This version has been extracted from the Turbogears source repository and slightly changed to be completely stand-alone again. Also some fixes have been made to make it work on Python 2.6 (sched module changes). The version in Turbogears is based on the original stand-alone Kronos. This is open-source software, released under the MIT Software License: http://www.opensource.org/licenses/mit-license.php """ __version__="2.0" __all__ = [ "DayTaskRescheduler", "ForkedIntervalTask", "ForkedMonthdayTask", "ForkedScheduler", "ForkedSingleTask", "ForkedTaskMixin", "ForkedWeekdayTask", "IntervalTask", "MonthdayTask", "Scheduler", "SingleTask", "Task", "ThreadedIntervalTask", "ThreadedMonthdayTask", "ThreadedScheduler", "ThreadedSingleTask", "ThreadedTaskMixin", "ThreadedWeekdayTask", "WeekdayTask", "add_interval_task", "add_monthday_task", "add_single_task", "add_weekday_task", "cancel", "method", ] import os import sys import sched import time import traceback import weakref import logging class method: sequential="sequential" forked="forked" threaded="threaded" class Scheduler: """The Scheduler itself.""" def __init__(self): self.running=True self.sched = sched.scheduler(time.time, self.__delayfunc) def __delayfunc(self, delay): # This delay function is basically a time.sleep() that is # divided up, so that we can check the self.running flag while delaying. # there is an additional check in here to ensure that the top item of # the queue hasn't changed if delay<10: time.sleep(delay) else: toptime = self._getqueuetoptime() endtime = time.time() + delay period = 5 stoptime = endtime - period while self.running and stoptime > time.time() and \ self._getqueuetoptime() == toptime: time.sleep(period) if not self.running or self._getqueuetoptime() != toptime: return now = time.time() if endtime > now: time.sleep(endtime - now) def _acquire_lock(self): pass def _release_lock(self): pass def add_interval_task(self, action, taskname, initialdelay, interval, processmethod, args, kw): """Add a new Interval Task to the schedule. A very short initialdelay or one of zero cannot be honored, you will see a slight delay before the task is first executed. This is because the scheduler needs to pick it up in its loop. """ if initialdelay < 0 or interval < 1: raise ValueError("Delay or interval must be >0") # Select the correct IntervalTask class. Not all types may be available! if processmethod == method.sequential: TaskClass = IntervalTask elif processmethod == method.threaded: TaskClass = ThreadedIntervalTask elif processmethod == method.forked: TaskClass = ForkedIntervalTask else: raise ValueError("Invalid processmethod") if not args: args = [] if not kw: kw = {} task = TaskClass(taskname, interval, action, args, kw) self.schedule_task(task, initialdelay) return task def add_single_task(self, action, taskname, initialdelay, processmethod, args, kw): """Add a new task to the scheduler that will only be executed once.""" if initialdelay < 0: raise ValueError("Delay must be >0") # Select the correct SingleTask class. Not all types may be available! if processmethod == method.sequential: TaskClass = SingleTask elif processmethod == method.threaded: TaskClass = ThreadedSingleTask elif processmethod == method.forked: TaskClass = ForkedSingleTask else: raise ValueError("Invalid processmethod") if not args: args = [] if not kw: kw = {} task = TaskClass(taskname, action, args, kw) self.schedule_task(task, initialdelay) return task def add_daytime_task(self, action, taskname, weekdays, monthdays, timeonday, processmethod, args, kw): """Add a new Day Task (Weekday or Monthday) to the schedule.""" if weekdays and monthdays: raise ValueError("You can only specify weekdays or monthdays, " "not both") if not args: args = [] if not kw: kw = {} if weekdays: # Select the correct WeekdayTask class. # Not all types may be available! if processmethod == method.sequential: TaskClass = WeekdayTask elif processmethod == method.threaded: TaskClass = ThreadedWeekdayTask elif processmethod == method.forked: TaskClass = ForkedWeekdayTask else: raise ValueError("Invalid processmethod") task=TaskClass(taskname, weekdays, timeonday, action, args, kw) if monthdays: # Select the correct MonthdayTask class. # Not all types may be available! if processmethod == method.sequential: TaskClass = MonthdayTask elif processmethod == method.threaded: TaskClass = ThreadedMonthdayTask elif processmethod == method.forked: TaskClass = ForkedMonthdayTask else: raise ValueError("Invalid processmethod") task=TaskClass(taskname, monthdays, timeonday, action, args, kw) firsttime=task.get_schedule_time(True) self.schedule_task_abs(task, firsttime) return task def schedule_task(self, task, delay): """Add a new task to the scheduler with the given delay (seconds). Low-level method for internal use. """ if self.running: # lock the sched queue, if needed self._acquire_lock() try: task.event = self.sched.enter(delay, 0, task, (weakref.ref(self),) ) finally: self._release_lock() else: task.event = self.sched.enter(delay, 0, task, (weakref.ref(self),) ) def schedule_task_abs(self, task, abstime): """Add a new task to the scheduler for the given absolute time value. Low-level method for internal use. """ if self.running: # lock the sched queue, if needed self._acquire_lock() try: task.event = self.sched.enterabs(abstime, 0, task, (weakref.ref(self),) ) finally: self._release_lock() else: task.event = self.sched.enterabs(abstime, 0, task, (weakref.ref(self),) ) def start(self): """Start the scheduler.""" self._run() def stop(self): """Remove all pending tasks and stop the Scheduler.""" self.running = False self._clearschedqueue() def cancel(self, task): """Cancel given scheduled task.""" self.sched.cancel(task.event) if sys.version_info>=(2,6): # code for sched module of python 2.6+ def _getqueuetoptime(self): try: return self.sched._queue[0].time except IndexError: return 0.0 def _clearschedqueue(self): self.sched._queue[:] = [] else: # code for sched module of python 2.5 and older def _getqueuetoptime(self): try: return self.sched.queue[0][0] except IndexError: return 0.0 def _clearschedqueue(self): self.sched.queue[:] = [] def _run(self): # Low-level run method to do the actual scheduling loop. while self.running: try: self.sched.run() except Exception,x: logging.error("ERROR DURING SCHEDULER EXECUTION %s" % str(x), exc_info=True) # queue is empty; sleep a short while before checking again if self.running: time.sleep(5) class Task: """Abstract base class of all scheduler tasks""" def __init__(self, name, action, args, kw): """This is an abstract class!""" self.name=name self.action=action self.args=args self.kw=kw def __call__(self, schedulerref): """Execute the task action in the scheduler's thread.""" try: self.execute() except Exception,x: self.handle_exception(x) self.reschedule(schedulerref()) def reschedule(self, scheduler): """This method should be defined in one of the sub classes!""" raise NotImplementedError("You're using the abstract base class 'Task'," " use a concrete class instead") def execute(self): """Execute the actual task.""" self.action(*self.args, **self.kw) def handle_exception(self, exc): """Handle any exception that occured during task execution.""" logging.error("ERROR DURING SCHEDULER EXECUTION %s" % str(exc), exc_info=True) class SingleTask(Task): """A task that only runs once.""" def reschedule(self, scheduler): pass class IntervalTask(Task): """A repeated task that occurs at certain intervals (in seconds).""" def __init__(self, name, interval, action, args=None, kw=None): Task.__init__(self, name, action, args, kw) self.interval = interval def reschedule(self, scheduler): """Reschedule this task according to its interval (in seconds).""" scheduler.schedule_task(self, self.interval) class DayTaskRescheduler: """A mixin class that contains the reschedule logic for the DayTasks.""" def __init__(self, timeonday): self.timeonday = timeonday def get_schedule_time(self, today): """Calculate the time value at which this task is to be scheduled.""" now = list(time.localtime()) if today: # schedule for today. let's see if that is still possible if (now[3], now[4]) >= self.timeonday: # too bad, it will be tomorrow now[2] += 1 else: # tomorrow now[2] += 1 # set new time on day (hour,minute) now[3], now[4] = self.timeonday # seconds now[5] = 0 return time.mktime(now) def reschedule(self, scheduler): """Reschedule this task according to the daytime for the task. The task is scheduled for tomorrow, for the given daytime. """ # (The execute method in the concrete Task classes will check # if the current day is a day on which the task must run). abstime = self.get_schedule_time(False) scheduler.schedule_task_abs(self, abstime) class WeekdayTask(DayTaskRescheduler, Task): """A task that is called at specific days in a week (1-7), at a fixed time on the day. """ def __init__(self, name, weekdays, timeonday, action, args=None, kw=None): if type(timeonday) not in (list, tuple) or len(timeonday) != 2: raise TypeError("timeonday must be a 2-tuple (hour,minute)") if type(weekdays) not in (list, tuple): raise TypeError("weekdays must be a sequence of weekday numbers " "1-7 (1 is Monday)") DayTaskRescheduler.__init__(self, timeonday) Task.__init__(self, name, action, args, kw) self.days = weekdays def execute(self): # This is called every day, at the correct time. We only need to # check if we should run this task today (this day of the week). weekday = time.localtime().tm_wday + 1 if weekday in self.days: self.action(*self.args, **self.kw) class MonthdayTask(DayTaskRescheduler, Task): """A task that is called at specific days in a month (1-31), at a fixed time on the day. """ def __init__(self, name, monthdays, timeonday, action, args=None, kw=None): if type(timeonday) not in (list, tuple) or len(timeonday) != 2: raise TypeError("timeonday must be a 2-tuple (hour,minute)") if type(monthdays) not in (list, tuple): raise TypeError("monthdays must be a sequence of monthdays numbers " "1-31") DayTaskRescheduler.__init__(self, timeonday) Task.__init__(self, name, action, args, kw) self.days = monthdays def execute(self): # This is called every day, at the correct time. We only need to # check if we should run this task today (this day of the month). if time.localtime().tm_mday in self.days: self.action(*self.args, **self.kw) try: import threading class ThreadedScheduler(Scheduler): """A Scheduler that runs in its own thread.""" def __init__(self): Scheduler.__init__(self) # we require a lock around the task queue self._lock = threading.Lock() def start(self): """Splice off a thread in which the scheduler will run.""" self.thread = threading.Thread(target=self._run) self.thread.setDaemon(True) self.thread.start() def stop(self): """Stop the scheduler and wait for the thread to finish.""" Scheduler.stop(self) try: self.thread.join() except AttributeError: pass def _acquire_lock(self): """Lock the thread's task queue.""" self._lock.acquire() def _release_lock(self): """Release the lock on th ethread's task queue.""" self._lock.release() class ThreadedTaskMixin: """A mixin class to make a Task execute in a separate thread.""" def __call__(self, schedulerref): """Execute the task action in its own thread.""" threading.Thread(target=self.threadedcall).start() self.reschedule(schedulerref()) def threadedcall(self): # This method is run within its own thread, so we have to # do the execute() call and exception handling here. try: self.execute() except Exception,x: self.handle_exception(x) class ThreadedIntervalTask(ThreadedTaskMixin, IntervalTask): """Interval Task that executes in its own thread.""" pass class ThreadedSingleTask(ThreadedTaskMixin, SingleTask): """Single Task that executes in its own thread.""" pass class ThreadedWeekdayTask(ThreadedTaskMixin, WeekdayTask): """Weekday Task that executes in its own thread.""" pass class ThreadedMonthdayTask(ThreadedTaskMixin, MonthdayTask): """Monthday Task that executes in its own thread.""" pass except ImportError: # threading is not available pass if hasattr(os, "fork"): import signal class ForkedScheduler(Scheduler): """A Scheduler that runs in its own forked process.""" def __del__(self): if hasattr(self, "childpid"): os.kill(self.childpid, signal.SIGKILL) def start(self): """Fork off a new process in which the scheduler will run.""" pid = os.fork() if pid == 0: # we are the child signal.signal(signal.SIGUSR1, self.signalhandler) self._run() os._exit(0) else: # we are the parent self.childpid = pid # can no longer insert in the scheduler queue del self.sched def stop(self): """Stop the scheduler and wait for the process to finish.""" os.kill(self.childpid, signal.SIGUSR1) os.waitpid(self.childpid, 0) def signalhandler(self, sig, stack): Scheduler.stop(self) class ForkedTaskMixin: """A mixin class to make a Task execute in a separate process.""" def __call__(self, schedulerref): """Execute the task action in its own process.""" pid = os.fork() if pid == 0: # we are the child try: self.execute() except Exception,x: self.handle_exception(x) os._exit(0) else: # we are the parent self.reschedule(schedulerref()) class ForkedIntervalTask(ForkedTaskMixin, IntervalTask): """Interval Task that executes in its own process.""" pass class ForkedSingleTask(ForkedTaskMixin, SingleTask): """Single Task that executes in its own process.""" pass class ForkedWeekdayTask(ForkedTaskMixin, WeekdayTask): """Weekday Task that executes in its own process.""" pass class ForkedMonthdayTask(ForkedTaskMixin, MonthdayTask): """Monthday Task that executes in its own process.""" pass if __name__=="__main__": def testaction(arg): print ">>>TASK",arg,"sleeping 3 seconds" time.sleep(3) print "<< # URL: http://code.google.com/p/sickbeard/ # # Sick Beard is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Sick Beard is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Sick Beard. If not, see . import os if os.name == 'nt': import win32api, win32con, win32file MASK = win32con.FILE_ATTRIBUTE_DIRECTORY | win32con.FILE_ATTRIBUTE_HIDDEN TMASK = win32con.FILE_ATTRIBUTE_DIRECTORY DRIVES = (2, 3, 4) NT = True else: NT = False import sabnzbd _JUNKFOLDERS = ( 'boot', 'bootmgr', 'cache', 'msocache', 'recovery', '$recycle.bin', 'recycler', 'system volume information', 'temporary internet files', # windows specific '.fseventd', '.spotlight', '.trashes', '.vol', 'cachedmessages', 'caches', 'trash' # osx specific ) # this is for the drive letter code, it only works on windows if os.name == 'nt': from ctypes import windll # adapted from http://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-drive-letters-in-python/827490 def get_win_drives(): """ Return list of detected drives """ assert NT drives = [] bitmask = windll.kernel32.GetLogicalDrives() for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': if (bitmask & 1) and win32file.GetDriveType('%s:\\' % letter) in DRIVES: drives.append(letter) bitmask >>= 1 return drives def folders_at_path(path, include_parent = False, show_hidden = False): """ Returns a list of dictionaries with the folders contained at the given path Give the empty string as the path to list the contents of the root path under Unix this means "/", on Windows this will be a list of drive letters) """ from sabnzbd.encoding import unicoder if path == "": if NT: entries = [{'name': letter + ':\\', 'path': letter + ':\\'} for letter in get_win_drives()] entries.insert(0, {'current_path': 'Root'}) return entries else: path = '/' # walk up the tree until we find a valid path path = sabnzbd.misc.real_path(sabnzbd.DIR_HOME, path) while path and not os.path.isdir(path): if path == os.path.dirname(path): return folders_at_path('', include_parent) else: path = os.path.dirname(path) # fix up the path and find the parent path = os.path.abspath(os.path.normpath(path)) parent_path = os.path.dirname(path) # if we're at the root then the next step is the meta-node showing our drive letters if path == parent_path and os.name == 'nt': parent_path = "" file_list = [] try: for filename in os.listdir(path): fpath = os.path.join(path, filename) try: if NT: doit = (win32api.GetFileAttributes(fpath) & MASK) == TMASK and filename != 'PerfLogs' elif not show_hidden: doit = not filename.startswith('.') else: doit = True except: doit = False if doit: file_list.append({ 'name': unicoder(filename), 'path': unicoder(fpath) }) file_list = filter(lambda entry: os.path.isdir(entry['path']), file_list) file_list = filter(lambda entry: entry['name'].lower() not in _JUNKFOLDERS, file_list) file_list = sorted(file_list, lambda x, y: cmp(os.path.basename(x['name']).lower(), os.path.basename(y['path']).lower())) except: # No access, ignore pass file_list.insert(0, {'current_path': path}) if include_parent and parent_path != path: file_list.insert(1,{ 'name': "..", 'path': parent_path }) return file_list SABnzbd-2.3.2/sabnzbd/utils/pybonjour.py0000644000000000000000000017377713217005257016343 0ustar 00000000000000################################################################################ # # Copyright (c) 2007-2008 Christopher J. Stawarz # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # ################################################################################ """ Pure-Python interface to Apple Bonjour and compatible DNS-SD libraries pybonjour provides a pure-Python interface (via ctypes) to Apple Bonjour and compatible DNS-SD libraries (such as Avahi). It allows Python scripts to take advantage of Zero Configuration Networking (Zeroconf) to register, discover, and resolve services on both local and wide-area networks. Since pybonjour is implemented in pure Python, scripts that use it can easily be ported to Mac OS X, Windows, Linux, and other systems that run Bonjour. Note on strings: Internally, all strings used in DNS-SD are UTF-8 strings. String arguments passed to the DNS-SD functions provided by pybonjour must be either unicode instances or str instances that can be converted to unicode using the default encoding. (Passing a non-convertible str will result in an exception.) Strings returned from pybonjour (either directly from API functions or passed to application callbacks) are always unicode instances. """ __author__ = 'Christopher Stawarz ' __version__ = '1.1.1' import ctypes import os import re import socket import sys ################################################################################ # # Global setup # ################################################################################ class _DummyLock(object): @staticmethod def acquire(): pass @staticmethod def release(): pass _global_lock = _DummyLock() if sys.platform == 'win32': # Need to use the stdcall variants _libdnssd = ctypes.windll.dnssd _CFunc = ctypes.WINFUNCTYPE else: if sys.platform == 'darwin': _libdnssd = 'libSystem.B.dylib' else: _libdnssd = 'libdns_sd.so.1' # If libdns_sd is actually Avahi's Bonjour compatibility # layer, silence its annoying warning messages, and use a real # RLock as the global lock, since the compatibility layer # isn't thread safe. try: ctypes.cdll.LoadLibrary('libavahi-client.so.3') except OSError: pass else: os.environ['AVAHI_COMPAT_NOWARN'] = '1' import threading _global_lock = threading.RLock() _libdnssd = ctypes.cdll.LoadLibrary(_libdnssd) _CFunc = ctypes.CFUNCTYPE ################################################################################ # # Constants # ################################################################################ # # General flags # kDNSServiceFlagsMoreComing = 0x1 kDNSServiceFlagsAdd = 0x2 kDNSServiceFlagsDefault = 0x4 kDNSServiceFlagsNoAutoRename = 0x8 kDNSServiceFlagsShared = 0x10 kDNSServiceFlagsUnique = 0x20 kDNSServiceFlagsBrowseDomains = 0x40 kDNSServiceFlagsRegistrationDomains = 0x80 kDNSServiceFlagsLongLivedQuery = 0x100 kDNSServiceFlagsAllowRemoteQuery = 0x200 kDNSServiceFlagsForceMulticast = 0x400 kDNSServiceFlagsReturnCNAME = 0x800 # # Service classes # kDNSServiceClass_IN = 1 # # Service types # kDNSServiceType_A = 1 kDNSServiceType_NS = 2 kDNSServiceType_MD = 3 kDNSServiceType_MF = 4 kDNSServiceType_CNAME = 5 kDNSServiceType_SOA = 6 kDNSServiceType_MB = 7 kDNSServiceType_MG = 8 kDNSServiceType_MR = 9 kDNSServiceType_NULL = 10 kDNSServiceType_WKS = 11 kDNSServiceType_PTR = 12 kDNSServiceType_HINFO = 13 kDNSServiceType_MINFO = 14 kDNSServiceType_MX = 15 kDNSServiceType_TXT = 16 kDNSServiceType_RP = 17 kDNSServiceType_AFSDB = 18 kDNSServiceType_X25 = 19 kDNSServiceType_ISDN = 20 kDNSServiceType_RT = 21 kDNSServiceType_NSAP = 22 kDNSServiceType_NSAP_PTR = 23 kDNSServiceType_SIG = 24 kDNSServiceType_KEY = 25 kDNSServiceType_PX = 26 kDNSServiceType_GPOS = 27 kDNSServiceType_AAAA = 28 kDNSServiceType_LOC = 29 kDNSServiceType_NXT = 30 kDNSServiceType_EID = 31 kDNSServiceType_NIMLOC = 32 kDNSServiceType_SRV = 33 kDNSServiceType_ATMA = 34 kDNSServiceType_NAPTR = 35 kDNSServiceType_KX = 36 kDNSServiceType_CERT = 37 kDNSServiceType_A6 = 38 kDNSServiceType_DNAME = 39 kDNSServiceType_SINK = 40 kDNSServiceType_OPT = 41 kDNSServiceType_TKEY = 249 kDNSServiceType_TSIG = 250 kDNSServiceType_IXFR = 251 kDNSServiceType_AXFR = 252 kDNSServiceType_MAILB = 253 kDNSServiceType_MAILA = 254 kDNSServiceType_ANY = 255 # # Error codes # kDNSServiceErr_NoError = 0 kDNSServiceErr_Unknown = -65537 kDNSServiceErr_NoSuchName = -65538 kDNSServiceErr_NoMemory = -65539 kDNSServiceErr_BadParam = -65540 kDNSServiceErr_BadReference = -65541 kDNSServiceErr_BadState = -65542 kDNSServiceErr_BadFlags = -65543 kDNSServiceErr_Unsupported = -65544 kDNSServiceErr_NotInitialized = -65545 kDNSServiceErr_AlreadyRegistered = -65547 kDNSServiceErr_NameConflict = -65548 kDNSServiceErr_Invalid = -65549 kDNSServiceErr_Firewall = -65550 kDNSServiceErr_Incompatible = -65551 kDNSServiceErr_BadInterfaceIndex = -65552 kDNSServiceErr_Refused = -65553 kDNSServiceErr_NoSuchRecord = -65554 kDNSServiceErr_NoAuth = -65555 kDNSServiceErr_NoSuchKey = -65556 kDNSServiceErr_NATTraversal = -65557 kDNSServiceErr_DoubleNAT = -65558 kDNSServiceErr_BadTime = -65559 # # Other constants # kDNSServiceMaxServiceName = 64 kDNSServiceMaxDomainName = 1005 kDNSServiceInterfaceIndexAny = 0 kDNSServiceInterfaceIndexLocalOnly = -1 ################################################################################ # # Error handling # ################################################################################ class BonjourError(Exception): """ Exception representing an error returned by the DNS-SD library. The errorCode attribute contains the actual integer error code returned. """ _errmsg = { kDNSServiceErr_NoSuchName: 'no such name', kDNSServiceErr_NoMemory: 'no memory', kDNSServiceErr_BadParam: 'bad param', kDNSServiceErr_BadReference: 'bad reference', kDNSServiceErr_BadState: 'bad state', kDNSServiceErr_BadFlags: 'bad flags', kDNSServiceErr_Unsupported: 'unsupported', kDNSServiceErr_NotInitialized: 'not initialized', kDNSServiceErr_AlreadyRegistered: 'already registered', kDNSServiceErr_NameConflict: 'name conflict', kDNSServiceErr_Invalid: 'invalid', kDNSServiceErr_Firewall: 'firewall', kDNSServiceErr_Incompatible: 'incompatible', kDNSServiceErr_BadInterfaceIndex: 'bad interface index', kDNSServiceErr_Refused: 'refused', kDNSServiceErr_NoSuchRecord: 'no such record', kDNSServiceErr_NoAuth: 'no auth', kDNSServiceErr_NoSuchKey: 'no such key', kDNSServiceErr_NATTraversal: 'NAT traversal', kDNSServiceErr_DoubleNAT: 'double NAT', kDNSServiceErr_BadTime: 'bad time', } @classmethod def _errcheck(cls, result, func, args): if result != kDNSServiceErr_NoError: raise cls(result) return args def __init__(self, errorCode): self.errorCode = errorCode Exception.__init__(self, (errorCode, self._errmsg.get(errorCode, 'unknown'))) ################################################################################ # # Data types # ################################################################################ class _utf8_char_p(ctypes.c_char_p): @classmethod def from_param(cls, obj): if (obj is not None) and (not isinstance(obj, cls)): if not isinstance(obj, basestring): raise TypeError('parameter must be a string type instance') if not isinstance(obj, unicode): obj = unicode(obj) obj = obj.encode('utf-8') return ctypes.c_char_p.from_param(obj) def decode(self): if self.value is None: return None return self.value.decode('utf-8') class _utf8_char_p_non_null(_utf8_char_p): @classmethod def from_param(cls, obj): if obj is None: raise ValueError('parameter cannot be None') return _utf8_char_p.from_param(obj) _DNSServiceFlags = ctypes.c_uint32 _DNSServiceErrorType = ctypes.c_int32 class DNSRecordRef(ctypes.c_void_p): """ A DNSRecordRef pointer. DO NOT CREATE INSTANCES OF THIS CLASS! Only instances returned by the DNS-SD library are valid. Using others will likely cause the Python interpreter to crash. Application code should not use any of the methods of this class. The only valid use of a DNSRecordRef instance is as an argument to a DNS-SD function. To compare two DNSRecordRef instances for equality, use '==' rather than 'is'. """ @classmethod def from_param(cls, obj): if type(obj) is not cls: raise TypeError("expected '%s', got '%s'" % (cls.__name__, type(obj).__name__)) if obj.value is None: raise ValueError('invalid %s instance' % cls.__name__) return obj def __eq__(self, other): return ((type(other) is type(self)) and (other.value == self.value)) def __ne__(self, other): return not (other == self) def _invalidate(self): self.value = None def _valid(self): return (self.value is not None) class _DNSRecordRef_or_null(DNSRecordRef): @classmethod def from_param(cls, obj): if obj is None: return obj return DNSRecordRef.from_param(obj) class DNSServiceRef(DNSRecordRef): """ A DNSServiceRef pointer. DO NOT CREATE INSTANCES OF THIS CLASS! Only instances returned by the DNS-SD library are valid. Using others will likely cause the Python interpreter to crash. An instance of this class represents an active connection to the mDNS daemon. The connection remains open until the close() method is called (which also terminates the associated browse, resolve, etc.). Note that this method is *not* called automatically when the instance is deallocated; therefore, application code must be certain to call close() when the connection is no longer needed. The primary use of a DNSServiceRef instance is in conjunction with select() or poll() to determine when a response from the daemon is available. When the file descriptor returned by fileno() is ready for reading, a reply from the daemon is available and should be processed by passing the DNSServiceRef instance to DNSServiceProcessResult(), which will invoke the appropriate application callback function. (Note that the file descriptor should never be read from or written to directly.) The DNSServiceRef class supports the context management protocol introduced in Python 2.5, meaning applications can use the 'with' statement to ensure that DNSServiceRef instances are closed regardless of whether an exception occurs, e.g. sdRef = DNSServiceBrowse(...) with sdRef: # sdRef will be closed regardless of how this block is # exited ... To compare two DNSServiceRef instances for equality, use '==' rather than 'is'. """ def __init__(self, *args, **kwargs): DNSRecordRef.__init__(self, *args, **kwargs) # Since callback functions are called asynchronously, we need # to hold onto references to them for as long as they're in # use. Otherwise, Python could deallocate them before we call # DNSServiceProcessResult(), meaning the Bonjour library would # dereference freed memory when it tried to invoke the # callback. self._callbacks = [] # A DNSRecordRef is invalidated if DNSServiceRefDeallocate() # is called on the corresponding DNSServiceRef, so we need to # keep track of all our record refs and invalidate them when # we're closed. self._record_refs = [] def __enter__(self): return self def __exit__(self, type, value, traceback): self.close() def _add_callback(self, cb): self._callbacks.append(cb) def _add_record_ref(self, ref): self._record_refs.append(ref) def close(self): """ Close the connection to the mDNS daemon and terminate any associated browse, resolve, etc. operations. """ if self._valid(): for ref in self._record_refs: ref._invalidate() del self._record_refs _global_lock.acquire() try: _DNSServiceRefDeallocate(self) finally: _global_lock.release() self._invalidate() del self._callbacks def fileno(self): """ Return the file descriptor associated with this connection. This descriptor should never be read from or written to directly. It should only be passed to select() or poll() to determine when a response from the mDNS daemon is available. """ _global_lock.acquire() try: fd = _DNSServiceRefSockFD(self) finally: _global_lock.release() return fd _DNSServiceDomainEnumReply = _CFunc( None, DNSServiceRef, # sdRef _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _DNSServiceErrorType, # errorCode _utf8_char_p, # replyDomain ctypes.c_void_p, # context ) _DNSServiceRegisterReply = _CFunc( None, DNSServiceRef, # sdRef _DNSServiceFlags, # flags _DNSServiceErrorType, # errorCode _utf8_char_p, # name _utf8_char_p, # regtype _utf8_char_p, # domain ctypes.c_void_p, # context ) _DNSServiceBrowseReply = _CFunc( None, DNSServiceRef, # sdRef _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _DNSServiceErrorType, # errorCode _utf8_char_p, # serviceName _utf8_char_p, # regtype _utf8_char_p, # replyDomain ctypes.c_void_p, # context ) _DNSServiceResolveReply = _CFunc( None, DNSServiceRef, # sdRef _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _DNSServiceErrorType, # errorCode _utf8_char_p, # fullname _utf8_char_p, # hosttarget ctypes.c_uint16, # port ctypes.c_uint16, # txtLen ctypes.c_void_p, # txtRecord (not null-terminated, so c_void_p) ctypes.c_void_p, # context ) _DNSServiceRegisterRecordReply = _CFunc( None, DNSServiceRef, # sdRef DNSRecordRef, # RecordRef _DNSServiceFlags, # flags _DNSServiceErrorType, # errorCode ctypes.c_void_p, # context ) _DNSServiceQueryRecordReply = _CFunc( None, DNSServiceRef, # sdRef _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _DNSServiceErrorType, # errorCode _utf8_char_p, # fullname ctypes.c_uint16, # rrtype ctypes.c_uint16, # rrclass ctypes.c_uint16, # rdlen ctypes.c_void_p, # rdata ctypes.c_uint32, # ttl ctypes.c_void_p, # context ) ################################################################################ # # Low-level function bindings # ################################################################################ def _create_function_bindings(): ERRCHECK = True NO_ERRCHECK = False OUTPARAM = (lambda index: index) NO_OUTPARAM = None specs = { #'funcname': #( # return_type, # errcheck, # outparam, # ( # param_1_type, # param_2_type, # ... # param_n_type, # )), 'DNSServiceRefSockFD': ( ctypes.c_int, NO_ERRCHECK, NO_OUTPARAM, ( DNSServiceRef, # sdRef )), 'DNSServiceProcessResult': ( _DNSServiceErrorType, ERRCHECK, NO_OUTPARAM, ( DNSServiceRef, # sdRef )), 'DNSServiceRefDeallocate': ( None, NO_ERRCHECK, NO_OUTPARAM, ( DNSServiceRef, # sdRef )), 'DNSServiceEnumerateDomains': ( _DNSServiceErrorType, ERRCHECK, OUTPARAM(0), ( ctypes.POINTER(DNSServiceRef), # sdRef _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _DNSServiceDomainEnumReply, # callBack ctypes.c_void_p, # context )), 'DNSServiceRegister': ( _DNSServiceErrorType, ERRCHECK, OUTPARAM(0), ( ctypes.POINTER(DNSServiceRef), # sdRef _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _utf8_char_p, # name _utf8_char_p_non_null, # regtype _utf8_char_p, # domain _utf8_char_p, # host ctypes.c_uint16, # port ctypes.c_uint16, # txtLen ctypes.c_void_p, # txtRecord _DNSServiceRegisterReply, # callBack ctypes.c_void_p, # context )), 'DNSServiceAddRecord': ( _DNSServiceErrorType, ERRCHECK, OUTPARAM(1), ( DNSServiceRef, # sdRef ctypes.POINTER(DNSRecordRef), # RecordRef _DNSServiceFlags, # flags ctypes.c_uint16, # rrtype ctypes.c_uint16, # rdlen ctypes.c_void_p, # rdata ctypes.c_uint32, # ttl )), 'DNSServiceUpdateRecord': ( _DNSServiceErrorType, ERRCHECK, NO_OUTPARAM, ( DNSServiceRef, # sdRef _DNSRecordRef_or_null, # RecordRef _DNSServiceFlags, # flags ctypes.c_uint16, # rdlen ctypes.c_void_p, # rdata ctypes.c_uint32, # ttl )), 'DNSServiceRemoveRecord': ( _DNSServiceErrorType, ERRCHECK, NO_OUTPARAM, ( DNSServiceRef, # sdRef DNSRecordRef, # RecordRef _DNSServiceFlags, # flags )), 'DNSServiceBrowse': ( _DNSServiceErrorType, ERRCHECK, OUTPARAM(0), ( ctypes.POINTER(DNSServiceRef), # sdRef _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _utf8_char_p_non_null, # regtype _utf8_char_p, # domain _DNSServiceBrowseReply, # callBack ctypes.c_void_p, # context )), 'DNSServiceResolve': ( _DNSServiceErrorType, ERRCHECK, OUTPARAM(0), ( ctypes.POINTER(DNSServiceRef), # sdRef _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _utf8_char_p_non_null, # name _utf8_char_p_non_null, # regtype _utf8_char_p_non_null, # domain _DNSServiceResolveReply, # callBack ctypes.c_void_p, # context )), 'DNSServiceCreateConnection': ( _DNSServiceErrorType, ERRCHECK, OUTPARAM(0), ( ctypes.POINTER(DNSServiceRef), # sdRef )), 'DNSServiceRegisterRecord': ( _DNSServiceErrorType, ERRCHECK, OUTPARAM(1), ( DNSServiceRef, # sdRef ctypes.POINTER(DNSRecordRef), # RecordRef _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _utf8_char_p_non_null, # fullname ctypes.c_uint16, # rrtype ctypes.c_uint16, # rrclass ctypes.c_uint16, # rdlen ctypes.c_void_p, # rdata ctypes.c_uint32, # ttl _DNSServiceRegisterRecordReply, # callBack ctypes.c_void_p, # context )), 'DNSServiceQueryRecord': ( _DNSServiceErrorType, ERRCHECK, OUTPARAM(0), ( ctypes.POINTER(DNSServiceRef), # sdRef _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _utf8_char_p_non_null, # fullname ctypes.c_uint16, # rrtype ctypes.c_uint16, # rrclass _DNSServiceQueryRecordReply, # callBack ctypes.c_void_p, # context )), 'DNSServiceReconfirmRecord': ( None, # _DNSServiceErrorType in more recent versions NO_ERRCHECK, NO_OUTPARAM, ( _DNSServiceFlags, # flags ctypes.c_uint32, # interfaceIndex _utf8_char_p_non_null, # fullname ctypes.c_uint16, # rrtype ctypes.c_uint16, # rrclass ctypes.c_uint16, # rdlen ctypes.c_void_p, # rdata )), 'DNSServiceConstructFullName': ( ctypes.c_int, ERRCHECK, OUTPARAM(0), ( ctypes.c_char * kDNSServiceMaxDomainName, # fullName _utf8_char_p, # service _utf8_char_p_non_null, # regtype _utf8_char_p_non_null, # domain )), } for name, (restype, errcheck, outparam, argtypes) in specs.iteritems(): prototype = _CFunc(restype, *argtypes) paramflags = [1] * len(argtypes) if outparam is not None: paramflags[outparam] = 2 paramflags = tuple((val,) for val in paramflags) func = prototype((name, _libdnssd), paramflags) if errcheck: func.errcheck = BonjourError._errcheck globals()['_' + name] = func # Only need to do this once _create_function_bindings() del _create_function_bindings ################################################################################ # # Internal utility types and functions # ################################################################################ class _NoDefault(object): def __repr__(self): return '' def check(self, obj): if obj is self: raise ValueError('required parameter value missing') _NO_DEFAULT = _NoDefault() def _string_to_length_and_void_p(string): if isinstance(string, TXTRecord): string = str(string) void_p = ctypes.cast(ctypes.c_char_p(string), ctypes.c_void_p) return len(string), void_p def _length_and_void_p_to_string(length, void_p): char_p = ctypes.cast(void_p, ctypes.POINTER(ctypes.c_char)) return ''.join(char_p[i] for i in xrange(length)) ################################################################################ # # High-level functions # ################################################################################ def DNSServiceProcessResult( sdRef, ): """ Read a reply from the daemon, calling the appropriate application callback. This call will block until the daemon's response is received. Use sdRef in conjunction with select() or poll() to determine the presence of a response from the server before calling this function to process the reply without blocking. Call this function at any point if it is acceptable to block until the daemon's response arrives. Note that the client is responsible for ensuring that DNSServiceProcessResult() is called whenever there is a reply from the daemon; the daemon may terminate its connection with a client that does not process the daemon's responses. sdRef: A DNSServiceRef returned by any of the DNSService calls that take a callback parameter. """ _global_lock.acquire() try: _DNSServiceProcessResult(sdRef) finally: _global_lock.release() def DNSServiceEnumerateDomains( flags, interfaceIndex = kDNSServiceInterfaceIndexAny, callBack = None, ): """ Asynchronously enumerate domains available for browsing and registration. The enumeration MUST be cancelled by closing the returned DNSServiceRef when no more domains are to be found. flags: Possible values are: kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing. kDNSServiceFlagsRegistrationDomains to enumerate domains recommended for registration. interfaceIndex: If non-zero, specifies the interface on which to look for domains. Most applications will pass kDNSServiceInterfaceIndexAny (0) to enumerate domains on all interfaces. callBack: The function to be called when a domain is found or the call asynchronously fails. Its signature should be callBack(sdRef, flags, interfaceIndex, errorCode, replyDomain). return value: A DNSServiceRef instance. Callback Parameters: sdRef: The DNSServiceRef returned by DNSServiceEnumerateDomains(). flags: Possible values are: kDNSServiceFlagsMoreComing kDNSServiceFlagsAdd kDNSServiceFlagsDefault interfaceIndex: Specifies the interface on which the domain exists. errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise indicates the failure that occurred (in which case other parameters are undefined). replyDomain: The name of the domain. """ @_DNSServiceDomainEnumReply def _callback(sdRef, flags, interfaceIndex, errorCode, replyDomain, context): if callBack is not None: callBack(sdRef, flags, interfaceIndex, errorCode, replyDomain.decode()) _global_lock.acquire() try: sdRef = _DNSServiceEnumerateDomains(flags, interfaceIndex, _callback, None) finally: _global_lock.release() sdRef._add_callback(_callback) return sdRef def DNSServiceRegister( flags = 0, interfaceIndex = kDNSServiceInterfaceIndexAny, name = None, regtype = _NO_DEFAULT, domain = None, host = None, port = _NO_DEFAULT, txtRecord = '', callBack = None, ): """ Register a service that is discovered via DNSServiceBrowse() and DNSServiceResolve() calls. flags: Indicates the renaming behavior on name conflict. Most applications will pass 0. interfaceIndex: If non-zero, specifies the interface on which to register the service. Most applications will pass kDNSServiceInterfaceIndexAny (0) to register on all available interfaces. name: If not None, specifies the service name to be registered. Most applications will not specify a name, in which case the computer name is used. (This name is communicated to the client via the callback.) If a name is specified, it must be 1-63 bytes of UTF-8 text. If the name is longer than 63 bytes, it will be automatically truncated to a legal length, unless the flag kDNSServiceFlagsNoAutoRename is set, in which case a BonjourError exception will be thrown. regtype: The service type followed by the protocol, separated by a dot (e.g. "_ftp._tcp"). The service type must be an underscore, followed by 1-14 characters, which may be letters, digits, or hyphens. The transport protocol must be "_tcp" or "_udp". New service types should be registered at . domain: If not None, specifies the domain on which to advertise the service. Most applications will not specify a domain, instead automatically registering in the default domain(s). host: If not None, specifies the SRV target host name. Most applications will not specify a host, instead automatically using the machine's default host name(s). Note that specifying a host name does NOT create an address record for that host; the application is responsible for ensuring that the appropriate address record exists, or creating it via DNSServiceRegisterRecord(). port: The port, in host (not network) byte order, on which the service accepts connections. Pass 0 for a "placeholder" service (i.e. a service that will not be discovered by browsing, but will cause a name conflict if another client tries to register that same name). Most clients will not use placeholder services. txtRecord: The TXT record rdata. If not None, txtRecord must be either a TXTRecord instance or a string containing a properly formatted DNS TXT record, i.e. ... callBack: The function to be called when the registration completes or asynchronously fails. Its signature should be callBack(sdRef, flags, errorCode, name, regtype, domain). The client MAY pass None for the callback, in which case the client will NOT be notified of the default values picked on its behalf, and the client will NOT be notified of any asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration of the service. The client may NOT pass the flag kDNSServiceFlagsNoAutoRename if the callback is None. The client may still deregister the service at any time by closing the returned DNSServiceRef. return value: A DNSServiceRef instance. The registration will remain active indefinitely until the client terminates it by closing the DNSServiceRef. Callback Parameters: sdRef: The DNSServiceRef returned by DNSServiceRegister(). flags: Currently unused, reserved for future use. errorCode: Will be kDNSServiceErr_NoError on success, otherwise will indicate the failure that occurred (including name conflicts, if the kDNSServiceFlagsNoAutoRename flag was used when registering). Other parameters are undefined if an error occurred. name: The service name registered. (If the application did not specify a name in DNSServiceRegister(), this indicates what name was automatically chosen.) regtype: The type of service registered, as it was passed to the callout. domain: The domain on which the service was registered. (If the application did not specify a domain in DNSServiceRegister(), this indicates the default domain on which the service was registered.) """ _NO_DEFAULT.check(regtype) _NO_DEFAULT.check(port) port = socket.htons(port) if not txtRecord: txtLen, txtRecord = 1, '\0' else: txtLen, txtRecord = _string_to_length_and_void_p(txtRecord) @_DNSServiceRegisterReply def _callback(sdRef, flags, errorCode, name, regtype, domain, context): if callBack is not None: callBack(sdRef, flags, errorCode, name.decode(), regtype.decode(), domain.decode()) _global_lock.acquire() try: sdRef = _DNSServiceRegister(flags, interfaceIndex, name, regtype, domain, host, port, txtLen, txtRecord, _callback, None) finally: _global_lock.release() sdRef._add_callback(_callback) return sdRef def DNSServiceAddRecord( sdRef, flags = 0, rrtype = _NO_DEFAULT, rdata = _NO_DEFAULT, ttl = 0, ): """ Add a record to a registered service. The name of the record will be the same as the registered service's name. The record can later be updated or deregistered by passing the DNSRecordRef returned by this function to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). Note that DNSServiceAddRecord/UpdateRecord/RemoveRecord are NOT thread-safe with respect to a single DNSServiceRef. If you plan to have multiple threads in your program simultaneously add, update, or remove records from the same DNSServiceRef, then it's the caller's responsibility to use a lock or take similar appropriate precautions to serialize those calls. sdRef: A DNSServiceRef returned by DNSServiceRegister(). flags: Currently ignored, reserved for future use. rrtype: The type of the record (e.g. kDNSServiceType_TXT, kDNSServiceType_SRV, etc.). rdata: A string containing the raw rdata to be contained in the added resource record. ttl: The time to live of the resource record, in seconds. Pass 0 to use a default value. return value: A DNSRecordRef instance, which may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). If sdRef is closed, the DNSRecordRef is also invalidated and may not be used further. """ _NO_DEFAULT.check(rrtype) _NO_DEFAULT.check(rdata) rdlen, rdata = _string_to_length_and_void_p(rdata) _global_lock.acquire() try: RecordRef = _DNSServiceAddRecord(sdRef, flags, rrtype, rdlen, rdata, ttl) finally: _global_lock.release() sdRef._add_record_ref(RecordRef) return RecordRef def DNSServiceUpdateRecord( sdRef, RecordRef = None, flags = 0, rdata = _NO_DEFAULT, ttl = 0, ): """ Update a registered resource record. The record must either be: - The primary txt record of a service registered via DNSServiceRegister(), or - A record added to a registered service via DNSServiceAddRecord(), or - An individual record registered by DNSServiceRegisterRecord() sdRef: A DNSServiceRef returned by DNSServiceRegister() or DNSServiceCreateConnection(). RecordRef: A DNSRecordRef returned by DNSServiceAddRecord(), or None to update the service's primary txt record. flags: Currently ignored, reserved for future use. rdata: A string containing the new rdata to be contained in the updated resource record. ttl: The time to live of the updated resource record, in seconds. """ _NO_DEFAULT.check(rdata) rdlen, rdata = _string_to_length_and_void_p(rdata) _global_lock.acquire() try: _DNSServiceUpdateRecord(sdRef, RecordRef, flags, rdlen, rdata, ttl) finally: _global_lock.release() def DNSServiceRemoveRecord( sdRef, RecordRef, flags = 0, ): """ Remove a record previously added to a service record set via DNSServiceAddRecord(), or deregister a record registered individually via DNSServiceRegisterRecord(). sdRef: A DNSServiceRef returned by DNSServiceRegister() (if the record being removed was registered via DNSServiceAddRecord()) or by DNSServiceCreateConnection() (if the record being removed was registered via DNSServiceRegisterRecord()). recordRef: A DNSRecordRef returned by DNSServiceAddRecord() or DNSServiceRegisterRecord(). flags: Currently ignored, reserved for future use. """ _global_lock.acquire() try: _DNSServiceRemoveRecord(sdRef, RecordRef, flags) finally: _global_lock.release() RecordRef._invalidate() def DNSServiceBrowse( flags = 0, interfaceIndex = kDNSServiceInterfaceIndexAny, regtype = _NO_DEFAULT, domain = None, callBack = None, ): """ Browse for instances of a service. flags: Currently ignored, reserved for future use. interfaceIndex: If non-zero, specifies the interface on which to browse for services. Most applications will pass kDNSServiceInterfaceIndexAny (0) to browse on all available interfaces. regtype: The service type being browsed for followed by the protocol, separated by a dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp". domain: If not None, specifies the domain on which to browse for services. Most applications will not specify a domain, instead browsing on the default domain(s). callBack: The function to be called when an instance of the service being browsed for is found, or if the call asynchronously fails. Its signature should be callBack(sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain). return value: A DNSServiceRef instance. The browse operation will run indefinitely until the client terminates it by closing the DNSServiceRef. Callback Parameters: sdRef: The DNSServiceRef returned by DNSServiceBrowse(). flags: Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd. interfaceIndex: The interface on which the service is advertised. This index should be passed to DNSServiceResolve() when resolving the service. errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will indicate the failure that occurred. Other parameters are undefined if an error occurred. serviceName: The discovered service name. This name should be displayed to the user and stored for subsequent use in the DNSServiceResolve() call. regtype: The service type, which is usually (but not always) the same as was passed to DNSServiceBrowse(). One case where the discovered service type may not be the same as the requested service type is when using subtypes: The client may want to browse for only those ftp servers that allow anonymous connections. The client will pass the string "_ftp._tcp,_anon" to DNSServiceBrowse(), but the type of the service that's discovered is simply "_ftp._tcp". The regtype for each discovered service instance should be stored along with the name, so that it can be passed to DNSServiceResolve() when the service is later resolved. replyDomain: The domain of the discovered service instance. This may or may not be the same as the domain that was passed to DNSServiceBrowse(). The domain for each discovered service instance should be stored along with the name, so that it can be passed to DNSServiceResolve() when the service is later resolved. """ _NO_DEFAULT.check(regtype) @_DNSServiceBrowseReply def _callback(sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain, context): if callBack is not None: callBack(sdRef, flags, interfaceIndex, errorCode, serviceName.decode(), regtype.decode(), replyDomain.decode()) _global_lock.acquire() try: sdRef = _DNSServiceBrowse(flags, interfaceIndex, regtype, domain, _callback, None) finally: _global_lock.release() sdRef._add_callback(_callback) return sdRef def DNSServiceResolve( flags = 0, interfaceIndex = _NO_DEFAULT, name = _NO_DEFAULT, regtype = _NO_DEFAULT, domain = _NO_DEFAULT, callBack = None, ): """ Resolve a service name discovered via DNSServiceBrowse() to a target host name, port number, and txt record. Note: Applications should NOT use DNSServiceResolve() solely for txt record monitoring; use DNSServiceQueryRecord() instead, as it is more efficient for this task. Note: When the desired results have been returned, the client MUST terminate the resolve by closing the returned DNSServiceRef. Note: DNSServiceResolve() behaves correctly for typical services that have a single SRV record and a single TXT record. To resolve non-standard services with multiple SRV or TXT records, DNSServiceQueryRecord() should be used. flags: Currently ignored, reserved for future use. interfaceIndex: The interface on which to resolve the service. If this resolve call is as a result of a currently active DNSServiceBrowse() operation, then the interfaceIndex should be the index reported in the browse callback. If this resolve call is using information previously saved (e.g. in a preference file) for later use, then use kDNSServiceInterfaceIndexAny (0), because the desired service may now be reachable via a different physical interface. name: The name of the service instance to be resolved, as reported to the DNSServiceBrowse() callback. regtype: The type of the service instance to be resolved, as reported to the DNSServiceBrowse() callback. domain: The domain of the service instance to be resolved, as reported to the DNSServiceBrowse() callback. callBack: The function to be called when a result is found, or if the call asynchronously fails. Its signature should be callBack(sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord). return value: A DNSServiceRef instance. The resolve operation will run indefinitely until the client terminates it by closing the DNSServiceRef. Callback Parameters: sdRef: The DNSServiceRef returned by DNSServiceResolve(). flags: Currently unused, reserved for future use. interfaceIndex: The interface on which the service was resolved. errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will indicate the failure that occurred. Other parameters are undefined if an error occurred. fullname: The full service domain name, in the form ... hosttarget: The target hostname of the machine providing the service. port: The port, in host (not network) byte order, on which connections are accepted for this service. txtRecord: A string containing the service's primary txt record, in standard txt record format. """ _NO_DEFAULT.check(interfaceIndex) _NO_DEFAULT.check(name) _NO_DEFAULT.check(regtype) _NO_DEFAULT.check(domain) @_DNSServiceResolveReply def _callback(sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtLen, txtRecord, context): if callBack is not None: port = socket.ntohs(port) txtRecord = _length_and_void_p_to_string(txtLen, txtRecord) callBack(sdRef, flags, interfaceIndex, errorCode, fullname.decode(), hosttarget.decode(), port, txtRecord) _global_lock.acquire() try: sdRef = _DNSServiceResolve(flags, interfaceIndex, name, regtype, domain, _callback, None) finally: _global_lock.release() sdRef._add_callback(_callback) return sdRef def DNSServiceCreateConnection(): """ Create a connection to the daemon allowing efficient registration of multiple individual records. return value: A DNSServiceRef instance. Closing it severs the connection and deregisters all records registered on this connection. """ _global_lock.acquire() try: sdRef = _DNSServiceCreateConnection() finally: _global_lock.release() return sdRef def DNSServiceRegisterRecord( sdRef, flags, interfaceIndex = kDNSServiceInterfaceIndexAny, fullname = _NO_DEFAULT, rrtype = _NO_DEFAULT, rrclass = kDNSServiceClass_IN, rdata = _NO_DEFAULT, ttl = 0, callBack = None, ): """ Register an individual resource record on a connected DNSServiceRef. Note that name conflicts occurring for records registered via this call must be handled by the client in the callback. sdRef: A DNSServiceRef returned by DNSServiceCreateConnection(). flags: Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique. interfaceIndex: If non-zero, specifies the interface on which to register the record. Passing kDNSServiceInterfaceIndexAny (0) causes the record to be registered on all interfaces. fullname: The full domain name of the resource record. rrtype: The numerical type of the resource record (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc.). rrclass: The class of the resource record (usually kDNSServiceClass_IN). rdata: A string containing the raw rdata, as it is to appear in the DNS record. ttl: The time to live of the resource record, in seconds. Pass 0 to use a default value. callBack: The function to be called when a result is found, or if the call asynchronously fails (e.g. because of a name conflict). Its signature should be callBack(sdRef, RecordRef, flags, errorCode). return value: A DNSRecordRef instance, which may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). (To deregister ALL records registered on a single connected DNSServiceRef and deallocate each of their corresponding DNSRecordRefs, close the DNSServiceRef.) Callback Parameters: sdRef: The connected DNSServiceRef returned by DNSServiceCreateConnection(). RecordRef: The DNSRecordRef returned by DNSServiceRegisterRecord(). flags: Currently unused, reserved for future use. errorCode: Will be kDNSServiceErr_NoError on success, otherwise will indicate the failure that occurred (including name conflicts). Other parameters are undefined if an error occurred. """ _NO_DEFAULT.check(fullname) _NO_DEFAULT.check(rrtype) _NO_DEFAULT.check(rdata) rdlen, rdata = _string_to_length_and_void_p(rdata) @_DNSServiceRegisterRecordReply def _callback(sdRef, RecordRef, flags, errorCode, context): if callBack is not None: callBack(sdRef, RecordRef, flags, errorCode) _global_lock.acquire() try: RecordRef = _DNSServiceRegisterRecord(sdRef, flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata, ttl, _callback, None) finally: _global_lock.release() sdRef._add_callback(_callback) sdRef._add_record_ref(RecordRef) return RecordRef def DNSServiceQueryRecord( flags = 0, interfaceIndex = kDNSServiceInterfaceIndexAny, fullname = _NO_DEFAULT, rrtype = _NO_DEFAULT, rrclass = kDNSServiceClass_IN, callBack = None, ): """ Query for an arbitrary DNS record. flags: Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast query in a non-local domain. Without setting this flag, unicast queries will be one-shot; that is, only answers available at the time of the call will be returned. By setting this flag, answers (including Add and Remove events) that become available after the initial call is made will generate callbacks. This flag has no effect on link-local multicast queries. interfaceIndex: If non-zero, specifies the interface on which to issue the query. Passing kDNSServiceInterfaceIndexAny (0) causes the name to be queried for on all interfaces. fullname: The full domain name of the resource record to be queried for. rrtype: The numerical type of the resource record to be queried for (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc.). rrclass: The class of the resource record (usually kDNSServiceClass_IN). callBack: The function to be called when a result is found, or if the call asynchronously fails. Its signature should be callBack(sdRef, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdata, ttl). return value: A DNSServiceRef instance. The query operation will run indefinitely until the client terminates it by closing the DNSServiceRef. Callback Parameters: sdRef: The DNSServiceRef returned by DNSServiceQueryRecord(). flags: Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd. The Add flag is NOT set for PTR records with a ttl of 0, i.e. "Remove" events. interfaceIndex: The interface on which the query was resolved. errorCode: Will be kDNSServiceErr_NoError on success, otherwise will indicate the failure that occurred. Other parameters are undefined if an error occurred. fullname: The resource record's full domain name. rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc.). rrclass: The class of the resource record (usually kDNSServiceClass_IN). rdata: A string containing the raw rdata of the resource record. ttl: The resource record's time to live, in seconds. """ _NO_DEFAULT.check(fullname) _NO_DEFAULT.check(rrtype) @_DNSServiceQueryRecordReply def _callback(sdRef, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdlen, rdata, ttl, context): if callBack is not None: rdata = _length_and_void_p_to_string(rdlen, rdata) callBack(sdRef, flags, interfaceIndex, errorCode, fullname.decode(), rrtype, rrclass, rdata, ttl) _global_lock.acquire() try: sdRef = _DNSServiceQueryRecord(flags, interfaceIndex, fullname, rrtype, rrclass, _callback, None) finally: _global_lock.release() sdRef._add_callback(_callback) return sdRef def DNSServiceReconfirmRecord( flags = 0, interfaceIndex = kDNSServiceInterfaceIndexAny, fullname = _NO_DEFAULT, rrtype = _NO_DEFAULT, rrclass = kDNSServiceClass_IN, rdata = _NO_DEFAULT, ): """ Instruct the daemon to verify the validity of a resource record that appears to be out of date (e.g. because tcp connection to a service's target failed). Causes the record to be flushed from the daemon's cache (as well as all other daemons' caches on the network) if the record is determined to be invalid. flags: Currently unused, reserved for future use. interfaceIndex: If non-zero, specifies the interface of the record in question. Passing kDNSServiceInterfaceIndexAny (0) causes all instances of this record to be reconfirmed. fullname: The resource record's full domain name. rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc.). rrclass: The class of the resource record (usually kDNSServiceClass_IN). rdata: A string containing the raw rdata of the resource record. """ _NO_DEFAULT.check(fullname) _NO_DEFAULT.check(rrtype) _NO_DEFAULT.check(rdata) rdlen, rdata = _string_to_length_and_void_p(rdata) _global_lock.acquire() try: _DNSServiceReconfirmRecord(flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata) finally: _global_lock.release() def DNSServiceConstructFullName( service = None, regtype = _NO_DEFAULT, domain = _NO_DEFAULT, ): """ Concatenate a three-part domain name (as returned by a callback function) into a properly-escaped full domain name. Note that callback functions already escape strings where necessary. service: The service name; any dots or backslashes must NOT be escaped. May be None (to construct a PTR record name, e.g. "_ftp._tcp.apple.com."). regtype: The service type followed by the protocol, separated by a dot (e.g. "_ftp._tcp"). domain: The domain name, e.g. "apple.com.". Literal dots or backslashes, if any, must be escaped, e.g. "1st\. Floor.apple.com." return value: The resulting full domain name. """ _NO_DEFAULT.check(regtype) _NO_DEFAULT.check(domain) _global_lock.acquire() try: fullName = _DNSServiceConstructFullName(service, regtype, domain) finally: _global_lock.release() return fullName.value.decode('utf-8') ################################################################################ # # TXTRecord class # ################################################################################ class TXTRecord(object): """ A mapping representing a DNS TXT record. The TXT record's name=value entries are stored as key/value pairs in the mapping. Although keys can be accessed in a case-insensitive fashion (meaning txt['foo'] and txt['FoO'] refer to the same value), key case is preserved in the wire representation of the record (so txt['FoO'] = 'bar' will generate a FoO=bar entry in the TXT record). Key order is also preserved, so keys appear in the wire format in the order in which they were created. Note that in addition to being valid as a txtRecord parameter to DNSServiceRegister(), a TXTRecord instance can be used in place of a resource record data string (i.e. rdata parameter) with any function that accepts one. """ def __init__(self, items={}, strict=True): """ Create a new TXTRecord instance, initializing it with the contents of items. If strict is true, then strict conformance to the DNS TXT record format will be enforced, and attempts to add a name containing invalid characters or a name/value pair whose wire representation is longer than 255 bytes will raise a ValueError exception. """ self.strict = strict self._names = [] self._items = {} for name, value in items.iteritems(): self[name] = value def __contains__(self, name): 'Return True if name is a key in the record, False otherwise' return (name.lower() in self._items) def __iter__(self): 'Return an iterator over name/value pairs' for name in self._names: yield self._items[name] def __len__(self): 'Return the number of name/value pairs' return len(self._names) def __nonzero__(self): 'Return False if the record is empty, True otherwise' return bool(self._items) def __str__(self): """ Return the wire representation of the TXT record as a string. If self.strict is false, any name/value pair whose wire length if greater than 255 bytes will be truncated to 255 bytes. If the record is empty, '\\0' is returned. """ if not self: return '\0' parts = [] for name, value in self: if value is None: item = name else: item = '%s=%s' % (name, value) if (not self.strict) and (len(item) > 255): item = item[:255] parts.append(chr(len(item))) parts.append(item) return ''.join(parts) def __getitem__(self, name): """ Return the value associated with name. The value is either None (meaning name has no associated value) or an str instance (which may be of length 0). Raises KeyError if name is not a key. """ return self._items[name.lower()][1] # Require one or more printable ASCII characters (0x20-0x7E), # excluding '=' (0x3D) _valid_name_re = re.compile(r'^[ -<>-~]+$') def __setitem__(self, name, value): """ Add a name/value pair to the record. If value is None, then name will have no associated value. If value is a unicode instance, it will be encoded as a UTF-8 string. Otherwise, value will be converted to an str instance. """ stored_name = name name = name.lower() length = len(name) if value is not None: if isinstance(value, unicode): value = value.encode('utf-8') else: value = str(value) length += 1 + len(value) if self.strict and (length > 255): raise ValueError('name=value string must be 255 bytes or less') if name not in self._items: if self.strict and (self._valid_name_re.match(stored_name) is None): raise ValueError("invalid name: '%s'" % stored_name) self._names.append(name) self._items[name] = (stored_name, value) def __delitem__(self, name): """ Remove name and its corresponding value from the record. Raises KeyError if name is not a key. """ name = name.lower() del self._items[name] self._names.remove(name) @classmethod def parse(cls, data, strict=False): """ Given a string data containing the wire representation of a DNS TXT record, parse it and return a TXTRecord instance. The strict parameter is passed to the TXTRecord constructor. """ txt = cls(strict=strict) while data: length = ord(data[0]) item = data[1:length+1].split('=', 1) # Add the item only if the name is non-empty and there are # no existing items with the same name if item[0] and (item[0] not in txt): if len(item) == 1: txt[item[0]] = None else: txt[item[0]] = item[1] data = data[length+1:] return txt SABnzbd-2.3.2/sabnzbd/utils/pystone.py0000644000000000000000000001630713217005257015776 0ustar 00000000000000#! /usr/bin/env python """ "PYSTONE" Benchmark Program Version: Python/1.1 (corresponds to C/1.1 plus 2 Pystone fixes) Author: Reinhold P. Weicker, CACM Vol 27, No 10, 10/84 pg. 1013. Translated from ADA to C by Rick Richardson. Every method to preserve ADA-likeness has been used, at the expense of C-ness. Translated from C to Python by Guido van Rossum. Version History: Version 1.1 corrects two bugs in version 1.0: First, it leaked memory: in Proc1(), NextRecord ends up having a pointer to itself. I have corrected this by zapping NextRecord.PtrComp at the end of Proc1(). Second, Proc3() used the operator != to compare a record to None. This is rather inefficient and not true to the intention of the original benchmark (where a pointer comparison to None is intended; the != operator attempts to find a method __cmp__ to do value comparison of the record). Version 1.1 runs 5-10 percent faster than version 1.0, so benchmark figures of different versions can't be compared directly. """ LOOPS = 50000 from time import clock __version__ = "1.1" [Ident1, Ident2, Ident3, Ident4, Ident5] = range(1, 6) class Record: def __init__(self, PtrComp = None, Discr = 0, EnumComp = 0, IntComp = 0, StringComp = 0): self.PtrComp = PtrComp self.Discr = Discr self.EnumComp = EnumComp self.IntComp = IntComp self.StringComp = StringComp def copy(self): return Record(self.PtrComp, self.Discr, self.EnumComp, self.IntComp, self.StringComp) TRUE = 1 FALSE = 0 def main(loops=LOOPS): benchtime, stones = pystones(loops) print "Pystone(%s) time for %d passes = %g" % \ (__version__, loops, benchtime) print "This machine benchmarks at %g pystones/second" % stones def pystones(loops=LOOPS): return Proc0(loops) IntGlob = 0 BoolGlob = FALSE Char1Glob = '\0' Char2Glob = '\0' Array1Glob = [0]*51 Array2Glob = map(lambda x: x[:], [Array1Glob]*51) PtrGlb = None PtrGlbNext = None def Proc0(loops=LOOPS): global IntGlob global BoolGlob global Char1Glob global Char2Glob global Array1Glob global Array2Glob global PtrGlb global PtrGlbNext starttime = clock() for i in range(loops): pass nulltime = clock() - starttime PtrGlbNext = Record() PtrGlb = Record() PtrGlb.PtrComp = PtrGlbNext PtrGlb.Discr = Ident1 PtrGlb.EnumComp = Ident3 PtrGlb.IntComp = 40 PtrGlb.StringComp = "DHRYSTONE PROGRAM, SOME STRING" String1Loc = "DHRYSTONE PROGRAM, 1'ST STRING" Array2Glob[8][7] = 10 starttime = clock() for i in range(loops): Proc5() Proc4() IntLoc1 = 2 IntLoc2 = 3 String2Loc = "DHRYSTONE PROGRAM, 2'ND STRING" EnumLoc = Ident2 BoolGlob = not Func2(String1Loc, String2Loc) while IntLoc1 < IntLoc2: IntLoc3 = 5 * IntLoc1 - IntLoc2 IntLoc3 = Proc7(IntLoc1, IntLoc2) IntLoc1 = IntLoc1 + 1 Proc8(Array1Glob, Array2Glob, IntLoc1, IntLoc3) PtrGlb = Proc1(PtrGlb) CharIndex = 'A' while CharIndex <= Char2Glob: if EnumLoc == Func1(CharIndex, 'C'): EnumLoc = Proc6(Ident1) CharIndex = chr(ord(CharIndex)+1) IntLoc3 = IntLoc2 * IntLoc1 IntLoc2 = IntLoc3 / IntLoc1 IntLoc2 = 7 * (IntLoc3 - IntLoc2) - IntLoc1 IntLoc1 = Proc2(IntLoc1) benchtime = clock() - starttime - nulltime if benchtime == 0.0: loopsPerBenchtime = 0.0 else: loopsPerBenchtime = (loops / benchtime) return benchtime, loopsPerBenchtime def Proc1(PtrParIn): PtrParIn.PtrComp = NextRecord = PtrGlb.copy() PtrParIn.IntComp = 5 NextRecord.IntComp = PtrParIn.IntComp NextRecord.PtrComp = PtrParIn.PtrComp NextRecord.PtrComp = Proc3(NextRecord.PtrComp) if NextRecord.Discr == Ident1: NextRecord.IntComp = 6 NextRecord.EnumComp = Proc6(PtrParIn.EnumComp) NextRecord.PtrComp = PtrGlb.PtrComp NextRecord.IntComp = Proc7(NextRecord.IntComp, 10) else: PtrParIn = NextRecord.copy() NextRecord.PtrComp = None return PtrParIn def Proc2(IntParIO): IntLoc = IntParIO + 10 while 1: if Char1Glob == 'A': IntLoc = IntLoc - 1 IntParIO = IntLoc - IntGlob EnumLoc = Ident1 if EnumLoc == Ident1: break return IntParIO def Proc3(PtrParOut): global IntGlob if PtrGlb is not None: PtrParOut = PtrGlb.PtrComp else: IntGlob = 100 PtrGlb.IntComp = Proc7(10, IntGlob) return PtrParOut def Proc4(): global Char2Glob BoolLoc = Char1Glob == 'A' BoolLoc = BoolLoc or BoolGlob Char2Glob = 'B' def Proc5(): global Char1Glob global BoolGlob Char1Glob = 'A' BoolGlob = FALSE def Proc6(EnumParIn): EnumParOut = EnumParIn if not Func3(EnumParIn): EnumParOut = Ident4 if EnumParIn == Ident1: EnumParOut = Ident1 elif EnumParIn == Ident2: if IntGlob > 100: EnumParOut = Ident1 else: EnumParOut = Ident4 elif EnumParIn == Ident3: EnumParOut = Ident2 elif EnumParIn == Ident4: pass elif EnumParIn == Ident5: EnumParOut = Ident3 return EnumParOut def Proc7(IntParI1, IntParI2): IntLoc = IntParI1 + 2 IntParOut = IntParI2 + IntLoc return IntParOut def Proc8(Array1Par, Array2Par, IntParI1, IntParI2): global IntGlob IntLoc = IntParI1 + 5 Array1Par[IntLoc] = IntParI2 Array1Par[IntLoc+1] = Array1Par[IntLoc] Array1Par[IntLoc+30] = IntLoc for IntIndex in range(IntLoc, IntLoc+2): Array2Par[IntLoc][IntIndex] = IntLoc Array2Par[IntLoc][IntLoc-1] = Array2Par[IntLoc][IntLoc-1] + 1 Array2Par[IntLoc+20][IntLoc] = Array1Par[IntLoc] IntGlob = 5 def Func1(CharPar1, CharPar2): CharLoc1 = CharPar1 CharLoc2 = CharLoc1 if CharLoc2 != CharPar2: return Ident1 else: return Ident2 def Func2(StrParI1, StrParI2): IntLoc = 1 while IntLoc <= 1: if Func1(StrParI1[IntLoc], StrParI2[IntLoc+1]) == Ident1: CharLoc = 'A' IntLoc = IntLoc + 1 if CharLoc >= 'W' and CharLoc <= 'Z': IntLoc = 7 if CharLoc == 'X': return TRUE else: if StrParI1 > StrParI2: IntLoc = IntLoc + 7 return TRUE else: return FALSE def Func3(EnumParIn): EnumLoc = EnumParIn if EnumLoc == Ident3: return TRUE return FALSE if __name__ == '__main__': import sys def error(msg): print >>sys.stderr, msg, print >>sys.stderr, "usage: %s [number_of_loops]" % sys.argv[0] sys.exit(100) nargs = len(sys.argv) - 1 if nargs > 1: error("%d arguments are too many;" % nargs) elif nargs == 1: try: loops = int(sys.argv[1]) except ValueError: error("Invalid argument %r;" % sys.argv[1]) else: loops = LOOPS main(loops) SABnzbd-2.3.2/sabnzbd/utils/rarfile.py0000644000000000000000000025063113217005257015721 0ustar 00000000000000# rarfile.py # # Copyright (c) 2005-2016 Marko Kreen # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. r"""RAR archive reader. This is Python module for Rar archive reading. The interface is made as :mod:`zipfile`-like as possible. Basic logic: - Parse archive structure with Python. - Extract non-compressed files with Python - Extract compressed files with unrar. - Optionally write compressed data to temp file to speed up unrar, otherwise it needs to scan whole archive on each execution. Example:: import rarfile rf = rarfile.RarFile('myarchive.rar') for f in rf.infolist(): print f.filename, f.file_size if f.filename == 'README': print(rf.read(f)) Archive files can also be accessed via file-like object returned by :meth:`RarFile.open`:: import rarfile with rarfile.RarFile('archive.rar') as rf: with rf.open('README') as f: for ln in f: print(ln.strip()) There are few module-level parameters to tune behaviour, here they are with defaults, and reason to change it:: import rarfile # Set to full path of unrar.exe if it is not in PATH rarfile.UNRAR_TOOL = "unrar" # Set to '\\' to be more compatible with old rarfile rarfile.PATH_SEP = '/' For more details, refer to source. """ from __future__ import division, print_function ## ## Imports and compat - support both Python 2.x and 3.x ## import sys import os import errno import struct from struct import pack, unpack, Struct from binascii import crc32, hexlify from tempfile import mkstemp from subprocess import Popen, PIPE, STDOUT from io import RawIOBase from hashlib import sha1, sha256 from hmac import HMAC from datetime import datetime, timedelta, tzinfo # fixed offset timezone, for UTC try: from datetime import timezone except ImportError: class timezone(tzinfo): """Compat timezone.""" __slots__ = ('_ofs', '_name') _DST = timedelta(0) def __init__(self, offset, name): super(timezone, self).__init__() self._ofs, self._name = offset, name def utcoffset(self, dt): return self._ofs def tzname(self, dt): return self._name def dst(self, dt): return self._DST # only needed for encryped headers try: try: from cryptography.hazmat.primitives.ciphers import algorithms, modes, Cipher from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf import pbkdf2 class AES_CBC_Decrypt(object): """Decrypt API""" def __init__(self, key, iv): ciph = Cipher(algorithms.AES(key), modes.CBC(iv), default_backend()) self.decrypt = ciph.decryptor().update def pbkdf2_sha256(password, salt, iters): """PBKDF2 with HMAC-SHA256""" ctx = pbkdf2.PBKDF2HMAC(hashes.SHA256(), 32, salt, iters, default_backend()) return ctx.derive(password) except ImportError: from Crypto.Cipher import AES from Crypto.Protocol import KDF class AES_CBC_Decrypt(object): """Decrypt API""" def __init__(self, key, iv): self.decrypt = AES.new(key, AES.MODE_CBC, iv).decrypt def pbkdf2_sha256(password, salt, iters): """PBKDF2 with HMAC-SHA256""" return KDF.PBKDF2(password, salt, 32, iters, hmac_sha256) _have_crypto = 1 except ImportError: _have_crypto = 0 try: from pyblake2 import blake2s _have_blake2 = True except ImportError: _have_blake2 = False # compat with 2.x if sys.hexversion < 0x3000000: def rar_crc32(data, prev=0): """CRC32 with unsigned values. """ if (prev > 0) and (prev & 0x80000000): prev -= (1 << 32) res = crc32(data, prev) if res < 0: res += (1 << 32) return res tohex = hexlify _byte_code = ord else: # pragma: no cover def tohex(data): """Return hex string.""" return hexlify(data).decode('ascii') rar_crc32 = crc32 unicode = str _byte_code = int # noqa __version__ = '3.0' # export only interesting items __all__ = ['is_rarfile', 'RarInfo', 'RarFile', 'RarExtFile'] ## ## Module configuration. Can be tuned after importing. ## #: default fallback charset DEFAULT_CHARSET = "windows-1252" #: list of encodings to try, with fallback to DEFAULT_CHARSET if none succeed TRY_ENCODINGS = ('utf8', 'utf-16le') #: 'unrar', 'rar' or full path to either one UNRAR_TOOL = "unrar" #: Command line args to use for opening file for reading. OPEN_ARGS = ('p', '-inul') #: Command line args to use for extracting file to disk. EXTRACT_ARGS = ('x', '-y', '-idq') #: args for testrar() TEST_ARGS = ('t', '-idq') # # Allow use of tool that is not compatible with unrar. # # By default use 'bsdtar' which is 'tar' program that # sits on top of libarchive. # # Problems with libarchive RAR backend: # - Does not support solid archives. # - Does not support password-protected archives. # ALT_TOOL = 'bsdtar' ALT_OPEN_ARGS = ('-x', '--to-stdout', '-f') ALT_EXTRACT_ARGS = ('-x', '-f') ALT_TEST_ARGS = ('-t', '-f') ALT_CHECK_ARGS = ('--help',) #: whether to speed up decompression by using tmp archive USE_EXTRACT_HACK = 0 #: limit the filesize for tmp archive usage HACK_SIZE_LIMIT = 20 * 1024 * 1024 #: Separator for path name components. RAR internally uses '\\'. #: Use '/' to be similar with zipfile. PATH_SEP = '/' ## ## rar constants ## # block types RAR_BLOCK_MARK = 0x72 # r RAR_BLOCK_MAIN = 0x73 # s RAR_BLOCK_FILE = 0x74 # t RAR_BLOCK_OLD_COMMENT = 0x75 # u RAR_BLOCK_OLD_EXTRA = 0x76 # v RAR_BLOCK_OLD_SUB = 0x77 # w RAR_BLOCK_OLD_RECOVERY = 0x78 # x RAR_BLOCK_OLD_AUTH = 0x79 # y RAR_BLOCK_SUB = 0x7a # z RAR_BLOCK_ENDARC = 0x7b # { # flags for RAR_BLOCK_MAIN RAR_MAIN_VOLUME = 0x0001 RAR_MAIN_COMMENT = 0x0002 RAR_MAIN_LOCK = 0x0004 RAR_MAIN_SOLID = 0x0008 RAR_MAIN_NEWNUMBERING = 0x0010 RAR_MAIN_AUTH = 0x0020 RAR_MAIN_RECOVERY = 0x0040 RAR_MAIN_PASSWORD = 0x0080 RAR_MAIN_FIRSTVOLUME = 0x0100 RAR_MAIN_ENCRYPTVER = 0x0200 # flags for RAR_BLOCK_FILE RAR_FILE_SPLIT_BEFORE = 0x0001 RAR_FILE_SPLIT_AFTER = 0x0002 RAR_FILE_PASSWORD = 0x0004 RAR_FILE_COMMENT = 0x0008 RAR_FILE_SOLID = 0x0010 RAR_FILE_DICTMASK = 0x00e0 RAR_FILE_DICT64 = 0x0000 RAR_FILE_DICT128 = 0x0020 RAR_FILE_DICT256 = 0x0040 RAR_FILE_DICT512 = 0x0060 RAR_FILE_DICT1024 = 0x0080 RAR_FILE_DICT2048 = 0x00a0 RAR_FILE_DICT4096 = 0x00c0 RAR_FILE_DIRECTORY = 0x00e0 RAR_FILE_LARGE = 0x0100 RAR_FILE_UNICODE = 0x0200 RAR_FILE_SALT = 0x0400 RAR_FILE_VERSION = 0x0800 RAR_FILE_EXTTIME = 0x1000 RAR_FILE_EXTFLAGS = 0x2000 # flags for RAR_BLOCK_ENDARC RAR_ENDARC_NEXT_VOLUME = 0x0001 RAR_ENDARC_DATACRC = 0x0002 RAR_ENDARC_REVSPACE = 0x0004 RAR_ENDARC_VOLNR = 0x0008 # flags common to all blocks RAR_SKIP_IF_UNKNOWN = 0x4000 RAR_LONG_BLOCK = 0x8000 # Host OS types RAR_OS_MSDOS = 0 RAR_OS_OS2 = 1 RAR_OS_WIN32 = 2 RAR_OS_UNIX = 3 RAR_OS_MACOS = 4 RAR_OS_BEOS = 5 # Compression methods - '0'..'5' RAR_M0 = 0x30 RAR_M1 = 0x31 RAR_M2 = 0x32 RAR_M3 = 0x33 RAR_M4 = 0x34 RAR_M5 = 0x35 # # RAR5 constants # RAR5_BLOCK_MAIN = 1 RAR5_BLOCK_FILE = 2 RAR5_BLOCK_SERVICE = 3 RAR5_BLOCK_ENCRYPTION = 4 RAR5_BLOCK_ENDARC = 5 RAR5_BLOCK_FLAG_EXTRA_DATA = 0x01 RAR5_BLOCK_FLAG_DATA_AREA = 0x02 RAR5_BLOCK_FLAG_SKIP_IF_UNKNOWN = 0x04 RAR5_BLOCK_FLAG_SPLIT_BEFORE = 0x08 RAR5_BLOCK_FLAG_SPLIT_AFTER = 0x10 RAR5_BLOCK_FLAG_DEPENDS_PREV = 0x20 RAR5_BLOCK_FLAG_KEEP_WITH_PARENT = 0x40 RAR5_MAIN_FLAG_ISVOL = 0x01 RAR5_MAIN_FLAG_HAS_VOLNR = 0x02 RAR5_MAIN_FLAG_SOLID = 0x04 RAR5_MAIN_FLAG_RECOVERY = 0x08 RAR5_MAIN_FLAG_LOCKED = 0x10 RAR5_FILE_FLAG_ISDIR = 0x01 RAR5_FILE_FLAG_HAS_MTIME = 0x02 RAR5_FILE_FLAG_HAS_CRC32 = 0x04 RAR5_FILE_FLAG_UNKNOWN_SIZE = 0x08 RAR5_COMPR_SOLID = 0x40 RAR5_ENC_FLAG_HAS_CHECKVAL = 0x01 RAR5_ENDARC_FLAG_NEXT_VOL = 0x01 RAR5_XFILE_ENCRYPTION = 1 RAR5_XFILE_HASH = 2 RAR5_XFILE_TIME = 3 RAR5_XFILE_VERSION = 4 RAR5_XFILE_REDIR = 5 RAR5_XFILE_OWNER = 6 RAR5_XFILE_SERVICE = 7 RAR5_XTIME_UNIXTIME = 0x01 RAR5_XTIME_HAS_MTIME = 0x02 RAR5_XTIME_HAS_CTIME = 0x04 RAR5_XTIME_HAS_ATIME = 0x08 RAR5_XENC_CIPHER_AES256 = 0 RAR5_XENC_CHECKVAL = 0x01 RAR5_XENC_TWEAKED = 0x02 RAR5_XHASH_BLAKE2SP = 0 RAR5_XREDIR_UNIX_SYMLINK = 1 RAR5_XREDIR_WINDOWS_SYMLINK = 2 RAR5_XREDIR_WINDOWS_JUNCTION = 3 RAR5_XREDIR_HARD_LINK = 4 RAR5_XREDIR_FILE_COPY = 5 RAR5_XREDIR_ISDIR = 0x01 RAR5_XOWNER_UNAME = 0x01 RAR5_XOWNER_GNAME = 0x02 RAR5_XOWNER_UID = 0x04 RAR5_XOWNER_GID = 0x08 RAR5_OS_WINDOWS = 0 RAR5_OS_UNIX = 1 ## ## internal constants ## RAR_ID = b"Rar!\x1a\x07\x00" RAR5_ID = b"Rar!\x1a\x07\x01\x00" ZERO = b'\0' EMPTY = b'' UTC = timezone(timedelta(0), 'UTC') BSIZE = 32 * 1024 def _get_rar_version(xfile): '''Check quickly whether file is rar archive. ''' with XFile(xfile) as fd: buf = fd.read(len(RAR5_ID)) if buf.startswith(RAR_ID): return 3 elif buf.startswith(RAR5_ID): return 5 return 0 ## ## Public interface ## def is_rarfile(xfile): '''Check quickly whether file is rar archive. ''' rar_ver = _get_rar_version(xfile) if rar_ver: return 'RAR%d' % rar_ver else: return None class Error(Exception): """Base class for rarfile errors.""" class BadRarFile(Error): """Incorrect data in archive.""" class NotRarFile(Error): """The file is not RAR archive.""" class BadRarName(Error): """Cannot guess multipart name components.""" class NoRarEntry(Error): """File not found in RAR""" class PasswordRequired(Error): """File requires password""" class NeedFirstVolume(Error): """Need to start from first volume.""" class NoCrypto(Error): """Cannot parse encrypted headers - no crypto available.""" class RarExecError(Error): """Problem reported by unrar/rar.""" class RarWarning(RarExecError): """Non-fatal error""" class RarFatalError(RarExecError): """Fatal error""" class RarCRCError(RarExecError): """CRC error during unpacking""" class RarLockedArchiveError(RarExecError): """Must not modify locked archive""" class RarWriteError(RarExecError): """Write error""" class RarOpenError(RarExecError): """Open error""" class RarUserError(RarExecError): """User error""" class RarMemoryError(RarExecError): """Memory error""" class RarCreateError(RarExecError): """Create error""" class RarNoFilesError(RarExecError): """No files that match pattern were found""" class RarUserBreak(RarExecError): """User stop""" class RarWrongPassword(RarExecError): """Incorrect password""" class RarUnknownError(RarExecError): """Unknown exit code""" class RarSignalExit(RarExecError): """Unrar exited with signal""" class RarCannotExec(RarExecError): """Executable not found.""" class RarInfo(object): r'''An entry in rar archive. RAR3 extended timestamps are :class:`datetime.datetime` objects without timezone. RAR5 extended timestamps are :class:`datetime.datetime` objects with UTC timezone. Attributes: filename File name with relative path. Path separator is '/'. Always unicode string. date_time File modification timestamp. As tuple of (year, month, day, hour, minute, second). RAR5 allows archives where it is missing, it's None then. file_size Uncompressed size. compress_size Compressed size. compress_type Compression method: one of :data:`RAR_M0` .. :data:`RAR_M5` constants. extract_version Minimal Rar version needed for decompressing. As (major*10 + minor), so 2.9 is 29. RAR3: 10, 20, 29 RAR5 does not have such field in archive, it's simply set to 50. host_os Host OS type, one of RAR_OS_* constants. RAR3: :data:`RAR_OS_WIN32`, :data:`RAR_OS_UNIX`, :data:`RAR_OS_MSDOS`, :data:`RAR_OS_OS2`, :data:`RAR_OS_BEOS`. RAR5: :data:`RAR_OS_WIN32`, :data:`RAR_OS_UNIX`. mode File attributes. May be either dos-style or unix-style, depending on host_os. mtime File modification time. Same value as :attr:`date_time` but as :class:`datetime.datetime` object with extended precision. ctime Optional time field: creation time. As :class:`datetime.datetime` object. atime Optional time field: last access time. As :class:`datetime.datetime` object. arctime Optional time field: archival time. As :class:`datetime.datetime` object. (RAR3-only) CRC CRC-32 of uncompressed file, unsigned int. RAR5: may be None. blake2sp_hash Blake2SP hash over decompressed data. (RAR5-only) comment Optional file comment field. Unicode string. (RAR3-only) file_redir If not None, file is link of some sort. Contains tuple of (type, flags, target). (RAR5-only) Type is one of constants: :data:`RAR5_XREDIR_UNIX_SYMLINK` unix symlink to target. :data:`RAR5_XREDIR_WINDOWS_SYMLINK` windows symlink to target. :data:`RAR5_XREDIR_WINDOWS_JUNCTION` windows junction. :data:`RAR5_XREDIR_HARD_LINK` hard link to target. :data:`RAR5_XREDIR_FILE_COPY` current file is copy of another archive entry. Flags may contain :data:`RAR5_XREDIR_ISDIR` bit. volume Volume nr, starting from 0. volume_file Volume file name, where file starts. ''' # zipfile-compatible fields filename = None file_size = None compress_size = None date_time = None comment = None CRC = None volume = None orig_filename = None # optional extended time fields, datetime() objects. mtime = None ctime = None atime = None extract_version = None mode = None host_os = None compress_type = None # rar3-only fields comment = None arctime = None # rar5-only fields blake2sp_hash = None file_redir = None # internal fields flags = 0 type = None def isdir(self): """Returns True if entry is a directory. """ if self.type == RAR_BLOCK_FILE: return (self.flags & RAR_FILE_DIRECTORY) == RAR_FILE_DIRECTORY return False def needs_password(self): """Returns True if data is stored password-protected. """ if self.type == RAR_BLOCK_FILE: return (self.flags & RAR_FILE_PASSWORD) > 0 return False class RarFile(object): '''Parse RAR structure, provide access to files in archive. ''' #: Archive comment. Unicode string or None. comment = None def __init__(self, rarfile, mode="r", charset=None, info_callback=None, crc_check=True, errors="stop", all_names=False): """Open and parse a RAR archive. Parameters: rarfile archive file name mode only 'r' is supported. charset fallback charset to use, if filenames are not already Unicode-enabled. info_callback debug callback, gets to see all archive entries. crc_check set to False to disable CRC checks errors Either "stop" to quietly stop parsing on errors, or "strict" to raise errors. Default is "stop". """ self._rarfile = rarfile self._charset = charset or DEFAULT_CHARSET self._info_callback = info_callback self._crc_check = crc_check self._password = None self._file_parser = None self._all_names = all_names if errors == "stop": self._strict = False elif errors == "strict": self._strict = True else: raise ValueError("Invalid value for 'errors' parameter.") if mode != "r": raise NotImplementedError("RarFile supports only mode=r") self._parse() def __enter__(self): return self def __exit__(self, typ, value, traceback): self.close() def setpassword(self, password): '''Sets the password to use when extracting.''' self._password = password if self._file_parser: if self._file_parser.has_header_encryption(): self._file_parser = None if not self._file_parser: self._parse() else: self._file_parser.setpassword(self._password) def needs_password(self): '''Returns True if any archive entries require password for extraction.''' return self._file_parser.needs_password() def namelist(self): '''Return list of file and foldernames in archive.''' return [f.filename for f in self.infolist()] def filelist(self): '''Return list of filenames in archive.''' return [f.filename for f in self.infolist() if not f.isdir()] def infolist(self): '''Return RarInfo objects for all files/directories in archive.''' return self._file_parser.infolist() def volumelist(self): '''Returns filenames of archive volumes. In case of single-volume archive, the list contains just the name of main archive file. ''' return self._file_parser.volumelist() def getinfo(self, fname): '''Return RarInfo for file. ''' return self._file_parser.getinfo(fname) def open(self, fname, mode='r', psw=None): '''Returns file-like object (:class:`RarExtFile`), from where the data can be read. The object implements :class:`io.RawIOBase` interface, so it can be further wrapped with :class:`io.BufferedReader` and :class:`io.TextIOWrapper`. On older Python where io module is not available, it implements only .read(), .seek(), .tell() and .close() methods. The object is seekable, although the seeking is fast only on uncompressed files, on compressed files the seeking is implemented by reading ahead and/or restarting the decompression. Parameters: fname file name or RarInfo instance. mode must be 'r' psw password to use for extracting. ''' if mode != 'r': raise NotImplementedError("RarFile.open() supports only mode=r") # entry lookup inf = self.getinfo(fname) if inf.isdir(): raise TypeError("Directory does not have any data: " + inf.filename) # check password if inf.needs_password(): psw = psw or self._password if psw is None: raise PasswordRequired("File %s requires password" % inf.filename) else: psw = None return self._file_parser.open(inf, psw) def read(self, fname, psw=None): """Return uncompressed data for archive entry. For longer files using :meth:`RarFile.open` may be better idea. Parameters: fname filename or RarInfo instance psw password to use for extracting. """ with self.open(fname, 'r', psw) as f: return f.read() def close(self): """Release open resources.""" pass def printdir(self): """Print archive file list to stdout.""" for f in self.infolist(): print(f.filename) def extract(self, member, path=None, pwd=None): """Extract single file into current directory. Parameters: member filename or :class:`RarInfo` instance path optional destination path pwd optional password to use """ if isinstance(member, RarInfo): fname = member.filename else: fname = member self._extract([fname], path, pwd) def extractall(self, path=None, members=None, pwd=None): """Extract all files into current directory. Parameters: path optional destination path members optional filename or :class:`RarInfo` instance list to extract pwd optional password to use """ fnlist = [] if members is not None: for m in members: if isinstance(m, RarInfo): fnlist.append(m.filename) else: fnlist.append(m) self._extract(fnlist, path, pwd) def testrar(self): """Let 'unrar' test the archive. """ # Modified for SABnzbd by clipping paths # and de-unicoding only here from sabnzbd.misc import clip_path from sabnzbd.encoding import deunicode rarpath = deunicode(clip_path(self._rarfile)) cmd = [UNRAR_TOOL] + list(TEST_ARGS) add_password_arg(cmd, self._password) cmd.append('--') with XTempFile(rarpath) as rarfile: cmd.append(rarfile) p = custom_popen(cmd) output = p.communicate()[0] check_returncode(p, output) def strerror(self): """Return error string if parsing failed, or None if no problems. """ if not self._file_parser: return "Not a RAR file" return self._file_parser.strerror() ## ## private methods ## def _parse(self): ver = _get_rar_version(self._rarfile) if ver == 3: p3 = RAR3Parser(self._rarfile, self._password, self._crc_check, self._charset, self._strict, self._info_callback, self._all_names) self._file_parser = p3 # noqa elif ver == 5: p5 = RAR5Parser(self._rarfile, self._password, self._crc_check, self._charset, self._strict, self._info_callback, self._all_names) self._file_parser = p5 # noqa else: raise BadRarFile("Not a RAR file") self._file_parser.parse() self.comment = self._file_parser.comment # call unrar to extract a file def _extract(self, fnlist, path=None, psw=None): cmd = [UNRAR_TOOL] + list(EXTRACT_ARGS) # pasoword psw = psw or self._password add_password_arg(cmd, psw) cmd.append('--') # rar file with XTempFile(self._rarfile) as rarfn: cmd.append(rarfn) # file list for fn in fnlist: if os.sep != PATH_SEP: fn = fn.replace(PATH_SEP, os.sep) cmd.append(fn) # destination path if path is not None: cmd.append(path + os.sep) # call p = custom_popen(cmd) output = p.communicate()[0] check_returncode(p, output) # # File format parsing # class CommonParser(object): """Shared parser parts.""" _main = None _hdrenc_main = None _needs_password = False _fd = None _expect_sig = None _parse_error = None _password = None comment = None def __init__(self, rarfile, password, crc_check, charset, strict, info_cb, all_names): self._rarfile = rarfile self._password = password self._crc_check = crc_check self._charset = charset self._strict = strict self._all_names = all_names self._info_callback = info_cb self._info_list = [] self._info_map = {} self._vol_list = [] def has_header_encryption(self): """Returns True if headers are encrypted """ if self._hdrenc_main: return True if self._main: if self._main.flags & RAR_MAIN_PASSWORD: return True return False def setpassword(self, psw): """Set cached password.""" self._password = psw def volumelist(self): """Volume files""" return self._vol_list def needs_password(self): """Is password required""" return self._needs_password def strerror(self): """Last error""" return self._parse_error def infolist(self): """List of RarInfo records. """ return self._info_list def getinfo(self, fname): """Return RarInfo for filename """ # accept both ways here if PATH_SEP == '/': fname2 = fname.replace("\\", "/") else: fname2 = fname.replace("/", "\\") try: return self._info_map[fname] except KeyError: try: return self._info_map[fname2] except KeyError: raise NoRarEntry("No such file: %s" % fname) # read rar def parse(self): """Process file.""" self._fd = None try: self._parse_real() finally: if self._fd: self._fd.close() self._fd = None def _parse_real(self): fd = XFile(self._rarfile) self._fd = fd sig = fd.read(len(self._expect_sig)) if sig != self._expect_sig: if isinstance(self._rarfile, (str, unicode)): raise NotRarFile("Not a Rar archive: {}".format(self._rarfile)) raise NotRarFile("Not a Rar archive") volume = 0 # first vol (.rar) is 0 more_vols = False endarc = False volfile = self._rarfile self._vol_list = [self._rarfile] while 1: if endarc: h = None # don't read past ENDARC else: h = self._parse_header(fd) if not h: if more_vols: volume += 1 fd.close() try: volfile = self._next_volname(volfile) fd = XFile(volfile) except IOError: self._set_error("Cannot open next volume: %s", volfile) break self._fd = fd sig = fd.read(len(self._expect_sig)) if sig != self._expect_sig: self._set_error("Invalid volume sig: %s", volfile) break more_vols = False endarc = False self._vol_list.append(volfile) continue break h.volume = volume h.volume_file = volfile if h.type == RAR_BLOCK_MAIN and not self._main: self._main = h if h.flags & RAR_MAIN_NEWNUMBERING: # RAR 2.x does not set FIRSTVOLUME, # so check it only if NEWNUMBERING is used if not self._all_names and (h.flags & RAR_MAIN_FIRSTVOLUME) == 0: raise NeedFirstVolume("Need to start from first volume") if h.flags & RAR_MAIN_PASSWORD: self._needs_password = True if not self._password: break elif h.type == RAR_BLOCK_ENDARC: more_vols = (h.flags & RAR_ENDARC_NEXT_VOLUME) > 0 endarc = True elif h.type == RAR_BLOCK_FILE: # RAR 2.x does not write RAR_BLOCK_ENDARC if h.flags & RAR_FILE_SPLIT_AFTER: more_vols = True # RAR 2.x does not set RAR_MAIN_FIRSTVOLUME if not self._all_names and volume == 0 and h.flags & RAR_FILE_SPLIT_BEFORE: raise NeedFirstVolume("Need to start from first volume") if h.needs_password(): self._needs_password = True # store it self.process_entry(fd, h) if self._info_callback: self._info_callback(h) # go to next header if h.add_size > 0: fd.seek(h.data_offset + h.add_size, 0) def process_entry(self, fd, item): """Examine item, add into lookup cache.""" raise NotImplementedError() def _decrypt_header(self, fd): raise NotImplementedError('_decrypt_header') def _parse_block_header(self, fd): raise NotImplementedError('_parse_block_header') def _open_hack(self, inf, psw): raise NotImplementedError('_open_hack') # read single header def _parse_header(self, fd): try: # handle encrypted headers if (self._main and self._main.flags & RAR_MAIN_PASSWORD) or self._hdrenc_main: if not self._password: return fd = self._decrypt_header(fd) # now read actual header return self._parse_block_header(fd) except struct.error: self._set_error('Broken header in RAR file') return None # given current vol name, construct next one def _next_volname(self, volfile): if is_filelike(volfile): raise IOError("Working on single FD") if self._main.flags & RAR_MAIN_NEWNUMBERING: return _next_newvol(volfile) return _next_oldvol(volfile) def _set_error(self, msg, *args): if args: msg = msg % args self._parse_error = msg if self._strict: raise BadRarFile(msg) def open(self, inf, psw): """Return stream object for file data.""" if inf.file_redir: # cannot leave to unrar as it expects copied file to exist if inf.file_redir[0] in (RAR5_XREDIR_FILE_COPY, RAR5_XREDIR_HARD_LINK): inf = self.getinfo(inf.file_redir[2]) if not inf: raise BadRarFile('cannot find copied file') if inf.flags & RAR_FILE_SPLIT_BEFORE: raise NeedFirstVolume("Partial file, please start from first volume: " + inf.filename) # is temp write usable? use_hack = 1 if not self._main: use_hack = 0 elif self._main._must_disable_hack(): use_hack = 0 elif inf._must_disable_hack(): use_hack = 0 elif is_filelike(self._rarfile): pass elif inf.file_size > HACK_SIZE_LIMIT: use_hack = 0 elif not USE_EXTRACT_HACK: use_hack = 0 # now extract if inf.compress_type == RAR_M0 and (inf.flags & RAR_FILE_PASSWORD) == 0 and inf.file_redir is None: return self._open_clear(inf) elif use_hack: return self._open_hack(inf, psw) elif is_filelike(self._rarfile): return self._open_unrar_membuf(self._rarfile, inf, psw) else: return self._open_unrar(self._rarfile, inf, psw) def _open_clear(self, inf): return DirectReader(self, inf) def _open_hack_core(self, inf, psw, prefix, suffix): size = inf.compress_size + inf.header_size rf = XFile(inf.volume_file, 0) rf.seek(inf.header_offset) tmpfd, tmpname = mkstemp(suffix='.rar') tmpf = os.fdopen(tmpfd, "wb") try: tmpf.write(prefix) while size > 0: if size > BSIZE: buf = rf.read(BSIZE) else: buf = rf.read(size) if not buf: raise BadRarFile('read failed: ' + inf.filename) tmpf.write(buf) size -= len(buf) tmpf.write(suffix) tmpf.close() rf.close() except: rf.close() tmpf.close() os.unlink(tmpname) raise return self._open_unrar(tmpname, inf, psw, tmpname) # write in-memory archive to temp file - needed for solid archives def _open_unrar_membuf(self, memfile, inf, psw): tmpname = membuf_tempfile(memfile) return self._open_unrar(tmpname, inf, psw, tmpname, force_file=True) # extract using unrar def _open_unrar(self, rarfile, inf, psw=None, tmpfile=None, force_file=False): cmd = [UNRAR_TOOL] + list(OPEN_ARGS) add_password_arg(cmd, psw) cmd.append("--") cmd.append(rarfile) # not giving filename avoids encoding related problems if not tmpfile or force_file: fn = inf.filename if PATH_SEP != os.sep: fn = fn.replace(PATH_SEP, os.sep) cmd.append(fn) # read from unrar pipe return PipeReader(self, inf, cmd, tmpfile) # # RAR3 format # class Rar3Info(RarInfo): """RAR3 specific fields.""" extract_version = 15 salt = None add_size = 0 header_crc = None header_size = None header_offset = None data_offset = None _md_class = None _md_expect = None # make sure some rar5 fields are always present file_redir = None blake2sp_hash = None def _must_disable_hack(self): if self.type == RAR_BLOCK_FILE: if self.flags & RAR_FILE_PASSWORD: return True elif self.flags & (RAR_FILE_SPLIT_BEFORE | RAR_FILE_SPLIT_AFTER): return True elif self.type == RAR_BLOCK_MAIN: if self.flags & (RAR_MAIN_SOLID | RAR_MAIN_PASSWORD): return True return False class RAR3Parser(CommonParser): """Parse RAR3 file format. """ _expect_sig = RAR_ID _last_aes_key = (None, None, None) # (salt, key, iv) def _decrypt_header(self, fd): if not _have_crypto: raise NoCrypto('Cannot parse encrypted headers - no crypto') salt = fd.read(8) if self._last_aes_key[0] == salt: key, iv = self._last_aes_key[1:] else: key, iv = rar3_s2k(self._password, salt) self._last_aes_key = (salt, key, iv) return HeaderDecrypt(fd, key, iv) # common header def _parse_block_header(self, fd): h = Rar3Info() h.header_offset = fd.tell() # read and parse base header buf = fd.read(S_BLK_HDR.size) if not buf: return None t = S_BLK_HDR.unpack_from(buf) h.header_crc, h.type, h.flags, h.header_size = t # read full header if h.header_size > S_BLK_HDR.size: hdata = buf + fd.read(h.header_size - S_BLK_HDR.size) else: hdata = buf h.data_offset = fd.tell() # unexpected EOF? if len(hdata) != h.header_size: self._set_error('Unexpected EOF when reading header') return None pos = S_BLK_HDR.size # block has data assiciated with it? if h.flags & RAR_LONG_BLOCK: h.add_size, pos = load_le32(hdata, pos) else: h.add_size = 0 # parse interesting ones, decide header boundaries for crc if h.type == RAR_BLOCK_MARK: return h elif h.type == RAR_BLOCK_MAIN: pos += 6 if h.flags & RAR_MAIN_ENCRYPTVER: pos += 1 crc_pos = pos if h.flags & RAR_MAIN_COMMENT: self._parse_subblocks(h, hdata, pos) elif h.type == RAR_BLOCK_FILE: pos = self._parse_file_header(h, hdata, pos - 4) crc_pos = pos if h.flags & RAR_FILE_COMMENT: pos = self._parse_subblocks(h, hdata, pos) elif h.type == RAR_BLOCK_SUB: pos = self._parse_file_header(h, hdata, pos - 4) crc_pos = h.header_size elif h.type == RAR_BLOCK_OLD_AUTH: pos += 8 crc_pos = pos elif h.type == RAR_BLOCK_OLD_EXTRA: pos += 7 crc_pos = pos else: crc_pos = h.header_size # check crc if h.type == RAR_BLOCK_OLD_SUB: crcdat = hdata[2:] + fd.read(h.add_size) else: crcdat = hdata[2:crc_pos] calc_crc = rar_crc32(crcdat) & 0xFFFF # return good header if h.header_crc == calc_crc: return h # header parsing failed. self._set_error('Header CRC error (%02x): exp=%x got=%x (xlen = %d)', h.type, h.header_crc, calc_crc, len(crcdat)) # instead panicing, send eof return None # read file-specific header def _parse_file_header(self, h, hdata, pos): fld = S_FILE_HDR.unpack_from(hdata, pos) pos += S_FILE_HDR.size h.compress_size = fld[0] h.file_size = fld[1] h.host_os = fld[2] h.CRC = fld[3] h.date_time = parse_dos_time(fld[4]) h.mtime = to_datetime(h.date_time) h.extract_version = fld[5] h.compress_type = fld[6] name_size = fld[7] h.mode = fld[8] h._md_class = CRC32Context h._md_expect = h.CRC if h.flags & RAR_FILE_LARGE: h1, pos = load_le32(hdata, pos) h2, pos = load_le32(hdata, pos) h.compress_size |= h1 << 32 h.file_size |= h2 << 32 h.add_size = h.compress_size name, pos = load_bytes(hdata, name_size, pos) if h.flags & RAR_FILE_UNICODE: nul = name.find(ZERO) h.orig_filename = name[:nul] u = UnicodeFilename(h.orig_filename, name[nul + 1:]) h.filename = u.decode() # if parsing failed fall back to simple name if u.failed: h.filename = self._decode(h.orig_filename) else: h.orig_filename = name h.filename = self._decode(name) # change separator, if requested if PATH_SEP != '\\': h.filename = h.filename.replace('\\', PATH_SEP) if h.flags & RAR_FILE_SALT: h.salt, pos = load_bytes(hdata, 8, pos) else: h.salt = None # optional extended time stamps if h.flags & RAR_FILE_EXTTIME: pos = _parse_ext_time(h, hdata, pos) else: h.mtime = h.atime = h.ctime = h.arctime = None return pos # find old-style comment subblock def _parse_subblocks(self, h, hdata, pos): while pos < len(hdata): # ordinary block header t = S_BLK_HDR.unpack_from(hdata, pos) ___scrc, stype, sflags, slen = t pos_next = pos + slen pos += S_BLK_HDR.size # corrupt header if pos_next < pos: break # followed by block-specific header if stype == RAR_BLOCK_OLD_COMMENT and pos + S_COMMENT_HDR.size <= pos_next: declen, ver, meth, crc = S_COMMENT_HDR.unpack_from(hdata, pos) pos += S_COMMENT_HDR.size data = hdata[pos : pos_next] cmt = rar3_decompress(ver, meth, data, declen, sflags, crc, self._password) if not self._crc_check: h.comment = self._decode_comment(cmt) elif rar_crc32(cmt) & 0xFFFF == crc: h.comment = self._decode_comment(cmt) pos = pos_next return pos def _read_comment_v3(self, inf, psw=None): # read data with XFile(inf.volume_file) as rf: rf.seek(inf.data_offset) data = rf.read(inf.compress_size) # decompress cmt = rar3_decompress(inf.extract_version, inf.compress_type, data, inf.file_size, inf.flags, inf.CRC, psw, inf.salt) # check crc if self._crc_check: crc = rar_crc32(cmt) if crc != inf.CRC: return None return self._decode_comment(cmt) def _decode(self, val): for c in TRY_ENCODINGS: try: return val.decode(c) except UnicodeError: pass return val.decode(self._charset, 'replace') def _decode_comment(self, val): return self._decode(val) def process_entry(self, fd, item): if item.type == RAR_BLOCK_FILE: # use only first part if (item.flags & RAR_FILE_SPLIT_BEFORE) == 0 : self._info_map[item.filename] = item self._info_list.append(item) elif self._all_names: # Broken rar-files would lead to double file-listings if item.filename not in self._info_map: self._info_map[item.filename] = item self._info_list.append(item) elif len(self._info_list) > 0: # final crc is in last block old = self._info_list[-1] old.CRC = item.CRC old._md_expect = item._md_expect old.compress_size += item.compress_size # parse new-style comment if item.type == RAR_BLOCK_SUB and item.filename == 'CMT': if item.flags & (RAR_FILE_SPLIT_BEFORE | RAR_FILE_SPLIT_AFTER): pass elif item.flags & RAR_FILE_SOLID: # file comment cmt = self._read_comment_v3(item, self._password) if len(self._info_list) > 0: old = self._info_list[-1] old.comment = cmt else: # archive comment cmt = self._read_comment_v3(item, self._password) self.comment = cmt if item.type == RAR_BLOCK_MAIN: if item.flags & RAR_MAIN_COMMENT: self.comment = item.comment if item.flags & RAR_MAIN_PASSWORD: self._needs_password = True # put file compressed data into temporary .rar archive, and run # unrar on that, thus avoiding unrar going over whole archive def _open_hack(self, inf, psw): # create main header: crc, type, flags, size, res1, res2 prefix = RAR_ID + S_BLK_HDR.pack(0x90CF, 0x73, 0, 13) + ZERO * (2 + 4) return self._open_hack_core(inf, psw, prefix, EMPTY) # # RAR5 format # class Rar5Info(RarInfo): """Shared fields for RAR5 records. """ extract_version = 50 header_crc = None header_size = None header_offset = None data_offset = None # type=all block_type = None block_flags = None add_size = 0 block_extra_size = 0 # type=MAIN volume_number = None _md_class = None _md_expect = None def _must_disable_hack(self): return False class Rar5BaseFile(Rar5Info): """Shared sturct for file & service record. """ type = -1 file_flags = None file_encryption = (0, 0, 0, EMPTY, EMPTY, EMPTY) file_compress_flags = None file_redir = None file_owner = None file_version = None blake2sp_hash = None def _must_disable_hack(self): if self.flags & RAR_FILE_PASSWORD: return True if self.block_flags & (RAR5_BLOCK_FLAG_SPLIT_BEFORE | RAR5_BLOCK_FLAG_SPLIT_AFTER): return True if self.file_compress_flags & RAR5_COMPR_SOLID: return True if self.file_redir: return True return False class Rar5FileInfo(Rar5BaseFile): """RAR5 file record. """ type = RAR_BLOCK_FILE class Rar5ServiceInfo(Rar5BaseFile): """RAR5 service record. """ type = RAR_BLOCK_SUB class Rar5MainInfo(Rar5Info): """RAR5 archive main record. """ type = RAR_BLOCK_MAIN main_flags = None main_volume_number = None def _must_disable_hack(self): if self.main_flags & RAR5_MAIN_FLAG_SOLID: return True return False class Rar5EncryptionInfo(Rar5Info): """RAR5 archive header encryption record. """ type = RAR5_BLOCK_ENCRYPTION encryption_algo = None encryption_flags = None encryption_kdf_count = None encryption_salt = None encryption_check_value = None def needs_password(self): return True class Rar5EndArcInfo(Rar5Info): """RAR5 end of archive record. """ type = RAR_BLOCK_ENDARC endarc_flags = None class RAR5Parser(CommonParser): """Parse RAR5 format. """ _expect_sig = RAR5_ID _hdrenc_main = None # AES encrypted headers _last_aes256_key = (-1, None, None) # (kdf_count, salt, key) def _gen_key(self, kdf_count, salt): if self._last_aes256_key[:2] == (kdf_count, salt): return self._last_aes256_key[2] if kdf_count > 24: raise BadRarFile('Too large kdf_count') psw = self._password if isinstance(psw, unicode): psw = psw.encode('utf8') key = pbkdf2_sha256(psw, salt, 1 << kdf_count) self._last_aes256_key = (kdf_count, salt, key) return key def _decrypt_header(self, fd): if not _have_crypto: raise NoCrypto('Cannot parse encrypted headers - no crypto') h = self._hdrenc_main key = self._gen_key(h.encryption_kdf_count, h.encryption_salt) iv = fd.read(16) return HeaderDecrypt(fd, key, iv) # common header def _parse_block_header(self, fd): header_offset = fd.tell() preload = 4 + 3 start_bytes = fd.read(preload) header_crc, pos = load_le32(start_bytes, 0) hdrlen, pos = load_vint(start_bytes, pos) if hdrlen > 2 * 1024 * 1024: return None header_size = pos + hdrlen # read full header, check for EOF hdata = start_bytes + fd.read(header_size - len(start_bytes)) if len(hdata) != header_size: self._set_error('Unexpected EOF when reading header') return None data_offset = fd.tell() calc_crc = rar_crc32(memoryview(hdata)[4:]) if header_crc != calc_crc: # header parsing failed. self._set_error('Header CRC error: exp=%x got=%x (xlen = %d)', header_crc, calc_crc, len(hdata)) return None block_type, pos = load_vint(hdata, pos) if block_type == RAR5_BLOCK_MAIN: h, pos = self._parse_block_common(Rar5MainInfo(), hdata) h = self._parse_main_block(h, hdata, pos) elif block_type == RAR5_BLOCK_FILE: h, pos = self._parse_block_common(Rar5FileInfo(), hdata) h = self._parse_file_block(h, hdata, pos) elif block_type == RAR5_BLOCK_SERVICE: h, pos = self._parse_block_common(Rar5ServiceInfo(), hdata) h = self._parse_file_block(h, hdata, pos) elif block_type == RAR5_BLOCK_ENCRYPTION: h, pos = self._parse_block_common(Rar5EncryptionInfo(), hdata) h = self._parse_encryption_block(h, hdata, pos) elif block_type == RAR5_BLOCK_ENDARC: h, pos = self._parse_block_common(Rar5EndArcInfo(), hdata) h = self._parse_endarc_block(h, hdata, pos) else: h = None if h: h.header_offset = header_offset h.data_offset = data_offset return h def _parse_block_common(self, h, hdata): h.header_crc, pos = load_le32(hdata, 0) hdrlen, pos = load_vint(hdata, pos) h.header_size = hdrlen + pos h.block_type, pos = load_vint(hdata, pos) h.block_flags, pos = load_vint(hdata, pos) if h.block_flags & RAR5_BLOCK_FLAG_EXTRA_DATA: h.block_extra_size, pos = load_vint(hdata, pos) if h.block_flags & RAR5_BLOCK_FLAG_DATA_AREA: h.add_size, pos = load_vint(hdata, pos) h.compress_size = h.add_size if h.block_flags & RAR5_BLOCK_FLAG_SKIP_IF_UNKNOWN: h.flags |= RAR_SKIP_IF_UNKNOWN if h.block_flags & RAR5_BLOCK_FLAG_DATA_AREA: h.flags |= RAR_LONG_BLOCK return h, pos def _parse_main_block(self, h, hdata, pos): h.main_flags, pos = load_vint(hdata, pos) if h.main_flags & RAR5_MAIN_FLAG_HAS_VOLNR: h.main_volume_number = load_vint(hdata, pos) h.flags |= RAR_MAIN_NEWNUMBERING if h.main_flags & RAR5_MAIN_FLAG_SOLID: h.flags |= RAR_MAIN_SOLID if h.main_flags & RAR5_MAIN_FLAG_ISVOL: h.flags |= RAR_MAIN_VOLUME if h.main_flags & RAR5_MAIN_FLAG_RECOVERY: h.flags |= RAR_MAIN_RECOVERY if self._hdrenc_main: h.flags |= RAR_MAIN_PASSWORD if h.main_flags & RAR5_MAIN_FLAG_HAS_VOLNR == 0: h.flags |= RAR_MAIN_FIRSTVOLUME return h def _parse_file_block(self, h, hdata, pos): h.file_flags, pos = load_vint(hdata, pos) h.file_size, pos = load_vint(hdata, pos) h.mode, pos = load_vint(hdata, pos) if h.file_flags & RAR5_FILE_FLAG_HAS_MTIME: h.mtime, pos = load_unixtime(hdata, pos) h.date_time = h.mtime.timetuple()[:6] if h.file_flags & RAR5_FILE_FLAG_HAS_CRC32: h.CRC, pos = load_le32(hdata, pos) h._md_class = CRC32Context h._md_expect = h.CRC h.file_compress_flags, pos = load_vint(hdata, pos) h.file_host_os, pos = load_vint(hdata, pos) h.orig_filename, pos = load_vstr(hdata, pos) h.filename = h.orig_filename.decode('utf8', 'replace') # use compatible values if h.file_host_os == RAR5_OS_WINDOWS: h.host_os = RAR_OS_WIN32 else: h.host_os = RAR_OS_UNIX h.compress_type = RAR_M0 + ((h.file_compress_flags >> 7) & 7) if h.block_extra_size: # allow 1 byte of garbage while pos < len(hdata) - 1: xsize, pos = load_vint(hdata, pos) xdata, pos = load_bytes(hdata, xsize, pos) self._process_file_extra(h, xdata) if h.block_flags & RAR5_BLOCK_FLAG_SPLIT_BEFORE: h.flags |= RAR_FILE_SPLIT_BEFORE if h.block_flags & RAR5_BLOCK_FLAG_SPLIT_AFTER: h.flags |= RAR_FILE_SPLIT_AFTER if h.file_flags & RAR5_FILE_FLAG_ISDIR: h.flags |= RAR_FILE_DIRECTORY if h.file_compress_flags & RAR5_COMPR_SOLID: h.flags |= RAR_FILE_SOLID return h def _parse_endarc_block(self, h, hdata, pos): h.endarc_flags, pos = load_vint(hdata, pos) if h.endarc_flags & RAR5_ENDARC_FLAG_NEXT_VOL: h.flags |= RAR_ENDARC_NEXT_VOLUME return h def _parse_encryption_block(self, h, hdata, pos): h.encryption_algo, pos = load_vint(hdata, pos) h.encryption_flags, pos = load_vint(hdata, pos) h.encryption_kdf_count, pos = load_byte(hdata, pos) h.encryption_salt, pos = load_bytes(hdata, 16, pos) if h.encryption_flags & RAR5_ENC_FLAG_HAS_CHECKVAL: h.encryption_check_value = load_bytes(hdata, 12, pos) if h.encryption_algo != RAR5_XENC_CIPHER_AES256: raise BadRarFile('Unsupported header encryption cipher') self._hdrenc_main = h return h # file extra record def _process_file_extra(self, h, xdata): xtype, pos = load_vint(xdata, 0) if xtype == RAR5_XFILE_TIME: self._parse_file_xtime(h, xdata, pos) elif xtype == RAR5_XFILE_ENCRYPTION: self._parse_file_encryption(h, xdata, pos) elif xtype == RAR5_XFILE_HASH: self._parse_file_hash(h, xdata, pos) elif xtype == RAR5_XFILE_VERSION: self._parse_file_version(h, xdata, pos) elif xtype == RAR5_XFILE_REDIR: self._parse_file_redir(h, xdata, pos) elif xtype == RAR5_XFILE_OWNER: self._parse_file_owner(h, xdata, pos) elif xtype == RAR5_XFILE_SERVICE: pass else: pass # extra block for file time record def _parse_file_xtime(self, h, xdata, pos): tflags, pos = load_vint(xdata, pos) ldr = load_windowstime if tflags & RAR5_XTIME_UNIXTIME: ldr = load_unixtime if tflags & RAR5_XTIME_HAS_MTIME: h.mtime, pos = ldr(xdata, pos) h.date_time = h.mtime.timetuple()[:6] if tflags & RAR5_XTIME_HAS_CTIME: h.ctime, pos = ldr(xdata, pos) if tflags & RAR5_XTIME_HAS_ATIME: h.atime, pos = ldr(xdata, pos) # just remember encryption info def _parse_file_encryption(self, h, xdata, pos): algo, pos = load_vint(xdata, pos) flags, pos = load_vint(xdata, pos) kdf_count, pos = load_byte(xdata, pos) salt, pos = load_bytes(xdata, 16, pos) iv, pos = load_bytes(xdata, 16, pos) checkval = None if flags & RAR5_XENC_CHECKVAL: checkval, pos = load_bytes(xdata, 12, pos) if flags & RAR5_XENC_TWEAKED: h._md_expect = None h._md_class = NoHashContext h.file_encryption = (algo, flags, kdf_count, salt, iv, checkval) h.flags |= RAR_FILE_PASSWORD def _parse_file_hash(self, h, xdata, pos): hash_type, pos = load_vint(xdata, pos) if hash_type == RAR5_XHASH_BLAKE2SP: h.blake2sp_hash, pos = load_bytes(xdata, 32, pos) if _have_blake2 and (h.file_encryption[1] & RAR5_XENC_TWEAKED) == 0: h._md_class = Blake2SP h._md_expect = h.blake2sp_hash def _parse_file_version(self, h, xdata, pos): flags, pos = load_vint(xdata, pos) version, pos = load_vint(xdata, pos) h.file_version = (flags, version) def _parse_file_redir(self, h, xdata, pos): redir_type, pos = load_vint(xdata, pos) redir_flags, pos = load_vint(xdata, pos) redir_name, pos = load_vstr(xdata, pos) redir_name = redir_name.decode('utf8', 'replace') h.file_redir = (redir_type, redir_flags, redir_name) def _parse_file_owner(self, h, xdata, pos): user_name = group_name = user_id = group_id = None flags, pos = load_vint(xdata, pos) if flags & RAR5_XOWNER_UNAME: user_name, pos = load_vstr(xdata, pos) if flags & RAR5_XOWNER_GNAME: group_name, pos = load_vstr(xdata, pos) if flags & RAR5_XOWNER_UID: user_id, pos = load_vint(xdata, pos) if flags & RAR5_XOWNER_GID: group_id, pos = load_vint(xdata, pos) h.file_owner = (user_name, group_name, user_id, group_id) def process_entry(self, fd, item): if item.block_type == RAR5_BLOCK_FILE: # use only first part if (item.block_flags & RAR5_BLOCK_FLAG_SPLIT_BEFORE) == 0: self._info_map[item.filename] = item self._info_list.append(item) elif self._all_names: # Broken rar-files would lead to double file-listings if item.filename not in self._info_map: self._info_map[item.filename] = item self._info_list.append(item) elif len(self._info_list) > 0: # final crc is in last block old = self._info_list[-1] old.CRC = item.CRC old._md_expect = item._md_expect old.blake2sp_hash = item.blake2sp_hash old.compress_size += item.compress_size elif item.block_type == RAR5_BLOCK_SERVICE: if item.filename == 'CMT': self._load_comment(fd, item) def _load_comment(self, fd, item): if item.block_flags & (RAR5_BLOCK_FLAG_SPLIT_BEFORE | RAR5_BLOCK_FLAG_SPLIT_AFTER): return None if item.compress_type != RAR_M0: return None if item.flags & RAR_FILE_PASSWORD: algo, ___flags, kdf_count, salt, iv, ___checkval = item.file_encryption if algo != RAR5_XENC_CIPHER_AES256: return None key = self._gen_key(kdf_count, salt) f = HeaderDecrypt(fd, key, iv) cmt = f.read(item.file_size) else: # archive comment with self._open_clear(item) as cmtstream: cmt = cmtstream.read() # rar bug? - appends zero to comment cmt = cmt.split(ZERO, 1)[0] self.comment = cmt.decode('utf8') def _open_hack(self, inf, psw): # len, type, blk_flags, flags main_hdr = b'\x03\x01\x00\x00' endarc_hdr = b'\x03\x05\x00\x00' main_hdr = S_LONG.pack(rar_crc32(main_hdr)) + main_hdr endarc_hdr = S_LONG.pack(rar_crc32(endarc_hdr)) + endarc_hdr return self._open_hack_core(inf, psw, RAR5_ID + main_hdr, endarc_hdr) ## ## Utility classes ## class UnicodeFilename(object): """Handle RAR3 unicode filename decompression. """ def __init__(self, name, encdata): self.std_name = bytearray(name) self.encdata = bytearray(encdata) self.pos = self.encpos = 0 self.buf = bytearray() self.failed = 0 def enc_byte(self): """Copy encoded byte.""" try: c = self.encdata[self.encpos] self.encpos += 1 return c except IndexError: self.failed = 1 return 0 def std_byte(self): """Copy byte from 8-bit representation.""" try: return self.std_name[self.pos] except IndexError: self.failed = 1 return ord('?') def put(self, lo, hi): """Copy 16-bit value to result.""" self.buf.append(lo) self.buf.append(hi) self.pos += 1 def decode(self): """Decompress compressed UTF16 value.""" hi = self.enc_byte() flagbits = 0 while self.encpos < len(self.encdata): if flagbits == 0: flags = self.enc_byte() flagbits = 8 flagbits -= 2 t = (flags >> flagbits) & 3 if t == 0: self.put(self.enc_byte(), 0) elif t == 1: self.put(self.enc_byte(), hi) elif t == 2: self.put(self.enc_byte(), self.enc_byte()) else: n = self.enc_byte() if n & 0x80: c = self.enc_byte() for _ in range((n & 0x7f) + 2): lo = (self.std_byte() + c) & 0xFF self.put(lo, hi) else: for _ in range(n + 2): self.put(self.std_byte(), 0) return self.buf.decode("utf-16le", "replace") class RarExtFile(RawIOBase): """Base class for file-like object that :meth:`RarFile.open` returns. Provides public methods and common crc checking. Behaviour: - no short reads - .read() and .readinfo() read as much as requested. - no internal buffer, use io.BufferedReader for that. """ #: Filename of the archive entry name = None def __init__(self, parser, inf): super(RarExtFile, self).__init__() # standard io.* properties self.name = inf.filename self.mode = 'rb' self._parser = parser self._inf = inf self._fd = None self._remain = 0 self._returncode = 0 self._md_context = None self._open() def _open(self): if self._fd: self._fd.close() md_class = self._inf._md_class or NoHashContext self._md_context = md_class() self._fd = None self._remain = self._inf.file_size def read(self, cnt=None): """Read all or specified amount of data from archive entry.""" # sanitize cnt if cnt is None or cnt < 0: cnt = self._remain elif cnt > self._remain: cnt = self._remain if cnt == 0: return EMPTY # actual read data = self._read(cnt) if data: self._md_context.update(data) self._remain -= len(data) if len(data) != cnt: raise BadRarFile("Failed the read enough data") # done? if not data or self._remain == 0: # self.close() self._check() return data def _check(self): """Check final CRC.""" final = self._md_context.digest() exp = self._inf._md_expect if exp is None: return if final is None: return if self._returncode: check_returncode(self, '') if self._remain != 0: raise BadRarFile("Failed the read enough data") if final != exp: raise BadRarFile("Corrupt file - CRC check failed: %s - exp=%r got=%r" % ( self._inf.filename, exp, final)) def _read(self, cnt): """Actual read that gets sanitized cnt.""" def close(self): """Close open resources.""" super(RarExtFile, self).close() if self._fd: self._fd.close() self._fd = None def __del__(self): """Hook delete to make sure tempfile is removed.""" self.close() def readinto(self, buf): """Zero-copy read directly into buffer. Returns bytes read. """ raise NotImplementedError('readinto') def tell(self): """Return current reading position in uncompressed data.""" return self._inf.file_size - self._remain def seek(self, ofs, whence=0): """Seek in data. On uncompressed files, the seeking works by actual seeks so it's fast. On compresses files its slow - forward seeking happends by reading ahead, backwards by re-opening and decompressing from the start. """ # disable crc check when seeking self._md_context = NoHashContext() fsize = self._inf.file_size cur_ofs = self.tell() if whence == 0: # seek from beginning of file new_ofs = ofs elif whence == 1: # seek from current position new_ofs = cur_ofs + ofs elif whence == 2: # seek from end of file new_ofs = fsize + ofs else: raise ValueError('Invalid value for whence') # sanity check if new_ofs < 0: new_ofs = 0 elif new_ofs > fsize: new_ofs = fsize # do the actual seek if new_ofs >= cur_ofs: self._skip(new_ofs - cur_ofs) else: # reopen and seek self._open() self._skip(new_ofs) return self.tell() def _skip(self, cnt): """Read and discard data""" while cnt > 0: if cnt > 8192: buf = self.read(8192) else: buf = self.read(cnt) if not buf: break cnt -= len(buf) def readable(self): """Returns True""" return True def writable(self): """Returns False. Writing is not supported.""" return False def seekable(self): """Returns True. Seeking is supported, although it's slow on compressed files. """ return True def readall(self): """Read all remaining data""" # avoid RawIOBase default impl return self.read() class PipeReader(RarExtFile): """Read data from pipe, handle tempfile cleanup.""" def __init__(self, rf, inf, cmd, tempfile=None): self._cmd = cmd self._proc = None self._tempfile = tempfile super(PipeReader, self).__init__(rf, inf) def _close_proc(self): if not self._proc: return if self._proc.stdout: self._proc.stdout.close() if self._proc.stdin: self._proc.stdin.close() if self._proc.stderr: self._proc.stderr.close() self._proc.wait() self._returncode = self._proc.returncode self._proc = None def _open(self): super(PipeReader, self)._open() # stop old process self._close_proc() # launch new process self._returncode = 0 self._proc = custom_popen(self._cmd) self._fd = self._proc.stdout # avoid situation where unrar waits on stdin if self._proc.stdin: self._proc.stdin.close() def _read(self, cnt): """Read from pipe.""" # normal read is usually enough data = self._fd.read(cnt) if len(data) == cnt or not data: return data # short read, try looping buf = [data] cnt -= len(data) while cnt > 0: data = self._fd.read(cnt) if not data: break cnt -= len(data) buf.append(data) return EMPTY.join(buf) def close(self): """Close open resources.""" self._close_proc() super(PipeReader, self).close() if self._tempfile: try: os.unlink(self._tempfile) except OSError: pass self._tempfile = None def readinto(self, buf): """Zero-copy read directly into buffer.""" cnt = len(buf) if cnt > self._remain: cnt = self._remain vbuf = memoryview(buf) res = got = 0 while got < cnt: res = self._fd.readinto(vbuf[got : cnt]) if not res: break self._md_context.update(vbuf[got : got + res]) self._remain -= res got += res return got class DirectReader(RarExtFile): """Read uncompressed data directly from archive. """ _cur = None _cur_avail = None _volfile = None def _open(self): super(DirectReader, self)._open() self._volfile = self._inf.volume_file self._fd = XFile(self._volfile, 0) self._fd.seek(self._inf.header_offset, 0) self._cur = self._parser._parse_header(self._fd) self._cur_avail = self._cur.add_size def _skip(self, cnt): """RAR Seek, skipping through rar files to get to correct position """ while cnt > 0: # next vol needed? if self._cur_avail == 0: if not self._open_next(): break # fd is in read pos, do the read if cnt > self._cur_avail: cnt -= self._cur_avail self._remain -= self._cur_avail self._cur_avail = 0 else: self._fd.seek(cnt, 1) self._cur_avail -= cnt self._remain -= cnt cnt = 0 def _read(self, cnt): """Read from potentially multi-volume archive.""" buf = [] while cnt > 0: # next vol needed? if self._cur_avail == 0: if not self._open_next(): break # fd is in read pos, do the read if cnt > self._cur_avail: data = self._fd.read(self._cur_avail) else: data = self._fd.read(cnt) if not data: break # got some data cnt -= len(data) self._cur_avail -= len(data) buf.append(data) if len(buf) == 1: return buf[0] return EMPTY.join(buf) def _open_next(self): """Proceed to next volume.""" # is the file split over archives? if (self._cur.flags & RAR_FILE_SPLIT_AFTER) == 0: return False if self._fd: self._fd.close() self._fd = None # open next part self._volfile = self._parser._next_volname(self._volfile) fd = open(self._volfile, "rb", 0) self._fd = fd sig = fd.read(len(self._parser._expect_sig)) if sig != self._parser._expect_sig: raise BadRarFile("Invalid signature") # loop until first file header while 1: cur = self._parser._parse_header(fd) if not cur: raise BadRarFile("Unexpected EOF") if cur.type in (RAR_BLOCK_MARK, RAR_BLOCK_MAIN): if cur.add_size: fd.seek(cur.add_size, 1) continue if cur.orig_filename != self._inf.orig_filename: raise BadRarFile("Did not found file entry") self._cur = cur self._cur_avail = cur.add_size return True def readinto(self, buf): """Zero-copy read directly into buffer.""" got = 0 vbuf = memoryview(buf) while got < len(buf): # next vol needed? if self._cur_avail == 0: if not self._open_next(): break # length for next read cnt = len(buf) - got if cnt > self._cur_avail: cnt = self._cur_avail # read into temp view res = self._fd.readinto(vbuf[got : got + cnt]) if not res: break self._md_context.update(vbuf[got : got + res]) self._cur_avail -= res self._remain -= res got += res return got class HeaderDecrypt(object): """File-like object that decrypts from another file""" def __init__(self, f, key, iv): self.f = f self.ciph = AES_CBC_Decrypt(key, iv) self.buf = EMPTY def tell(self): """Current file pos - works only on block boundaries.""" return self.f.tell() def read(self, cnt=None): """Read and decrypt.""" if cnt > 8 * 1024: raise BadRarFile('Bad count to header decrypt - wrong password?') # consume old data if cnt <= len(self.buf): res = self.buf[:cnt] self.buf = self.buf[cnt:] return res res = self.buf self.buf = EMPTY cnt -= len(res) # decrypt new data blklen = 16 while cnt > 0: enc = self.f.read(blklen) if len(enc) < blklen: break dec = self.ciph.decrypt(enc) if cnt >= len(dec): res += dec cnt -= len(dec) else: res += dec[:cnt] self.buf = dec[cnt:] cnt = 0 return res # handle (filename|filelike) object class XFile(object): """Input may be filename or file object. """ __slots__ = ('_fd', '_need_close') def __init__(self, xfile, bufsize=1024): if is_filelike(xfile): self._need_close = False self._fd = xfile self._fd.seek(0) else: self._need_close = True self._fd = open(xfile, 'rb', bufsize) def read(self, n=None): """Read from file.""" return self._fd.read(n) def tell(self): """Return file pos.""" return self._fd.tell() def seek(self, ofs, whence=0): """Move file pos.""" return self._fd.seek(ofs, whence) def readinto(self, dst): """Read into buffer.""" return self._fd.readinto(dst) def close(self): """Close file object.""" if self._need_close: self._fd.close() def __enter__(self): return self def __exit__(self, typ, val, tb): self.close() class NoHashContext(object): """No-op hash function.""" def __init__(self, data=None): """Initialize""" def update(self, data): """Update data""" def digest(self): """Final hash""" def hexdigest(self): """Hexadecimal digest.""" class CRC32Context(object): """Hash context that uses CRC32.""" __slots__ = ['_crc'] def __init__(self, data=None): self._crc = 0 if data: self.update(data) def update(self, data): """Process data.""" self._crc = rar_crc32(data, self._crc) def digest(self): """Final hash.""" return self._crc def hexdigest(self): """Hexadecimal digest.""" return '%08x' % self.digest() class Blake2SP(object): """Blake2sp hash context. """ __slots__ = ['_thread', '_buf', '_cur', '_digest'] digest_size = 32 block_size = 64 parallelism = 8 def __init__(self, data=None): self._buf = b'' self._cur = 0 self._digest = None self._thread = [] for i in range(self.parallelism): ctx = self._blake2s(i, 0, i == (self.parallelism - 1)) self._thread.append(ctx) if data: self.update(data) def _blake2s(self, ofs, depth, is_last): return blake2s(node_offset=ofs, node_depth=depth, last_node=is_last, depth=2, inner_size=32, fanout=self.parallelism) def _add_block(self, blk): self._thread[self._cur].update(blk) self._cur = (self._cur + 1) % self.parallelism def update(self, data): """Hash data. """ view = memoryview(data) bs = self.block_size if self._buf: need = bs - len(self._buf) if len(view) < need: self._buf += view.tobytes() return self._add_block(self._buf + view[:need].tobytes()) view = view[need:] while len(view) >= bs: self._add_block(view[:bs]) view = view[bs:] self._buf = view.tobytes() def digest(self): """Return final digest value. """ if self._digest is None: if self._buf: self._add_block(self._buf) self._buf = EMPTY ctx = self._blake2s(0, 1, True) for t in self._thread: ctx.update(t.digest()) self._digest = ctx.digest() return self._digest def hexdigest(self): """Hexadecimal digest.""" return tohex(self.digest()) ## ## Utility functions ## S_LONG = Struct(' len(buf): raise BadRarFile('cannot load byte') return S_BYTE.unpack_from(buf, pos)[0], end def load_le32(buf, pos): """Load little-endian 32-bit integer""" end = pos + 4 if end > len(buf): raise BadRarFile('cannot load le32') return S_LONG.unpack_from(buf, pos)[0], pos + 4 def load_bytes(buf, num, pos): """Load sequence of bytes""" end = pos + num if end > len(buf): raise BadRarFile('cannot load bytes') return buf[pos : end], end def load_vstr(buf, pos): """Load bytes prefixed by vint length""" slen, pos = load_vint(buf, pos) return load_bytes(buf, slen, pos) def load_dostime(buf, pos): """Load LE32 dos timestamp""" stamp, pos = load_le32(buf, pos) tup = parse_dos_time(stamp) return to_datetime(tup), pos def load_unixtime(buf, pos): """Load LE32 unix timestamp""" secs, pos = load_le32(buf, pos) dt = datetime.fromtimestamp(secs, UTC) return dt, pos def load_windowstime(buf, pos): """Load LE64 windows timestamp""" # unix epoch (1970) in seconds from windows epoch (1601) unix_epoch = 11644473600 val1, pos = load_le32(buf, pos) val2, pos = load_le32(buf, pos) secs, n1secs = divmod((val2 << 32) | val1, 10000000) dt = datetime.fromtimestamp(secs - unix_epoch, UTC) dt = dt.replace(microsecond=n1secs // 10) return dt, pos # new-style next volume def _next_newvol(volfile): i = len(volfile) - 1 while i >= 0: if volfile[i] >= '0' and volfile[i] <= '9': return _inc_volname(volfile, i) i -= 1 raise BadRarName("Cannot construct volume name: " + volfile) # old-style next volume def _next_oldvol(volfile): # rar -> r00 if volfile[-4:].lower() == '.rar': return volfile[:-2] + '00' return _inc_volname(volfile, len(volfile) - 1) # increase digits with carry, otherwise just increment char def _inc_volname(volfile, i): fn = list(volfile) while i >= 0: if fn[i] != '9': fn[i] = chr(ord(fn[i]) + 1) break fn[i] = '0' i -= 1 return ''.join(fn) # rar3 extended time fields def _parse_ext_time(h, data, pos): # flags and rest of data can be missing flags = 0 if pos + 2 <= len(data): flags = S_SHORT.unpack_from(data, pos)[0] pos += 2 mtime, pos = _parse_xtime(flags >> 3 * 4, data, pos, h.mtime) h.ctime, pos = _parse_xtime(flags >> 2 * 4, data, pos) h.atime, pos = _parse_xtime(flags >> 1 * 4, data, pos) h.arctime, pos = _parse_xtime(flags >> 0 * 4, data, pos) if mtime: h.mtime = mtime h.date_time = mtime.timetuple()[:6] return pos # rar3 one extended time field def _parse_xtime(flag, data, pos, basetime=None): res = None if flag & 8: if not basetime: basetime, pos = load_dostime(data, pos) # load second fractions rem = 0 cnt = flag & 3 for _ in range(cnt): b, pos = load_byte(data, pos) rem = (b << 16) | (rem >> 8) # convert 100ns units to microseconds usec = rem // 10 if usec > 1000000: usec = 999999 # dostime has room for 30 seconds only, correct if needed if flag & 4 and basetime.second < 59: res = basetime.replace(microsecond=usec, second=basetime.second + 1) else: res = basetime.replace(microsecond=usec) return res, pos def is_filelike(obj): """Filename or file object? """ if isinstance(obj, str) or isinstance(obj, unicode): return False res = True for a in ('read', 'tell', 'seek'): res = res and hasattr(obj, a) if not res: raise ValueError("Invalid object passed as file") return True def rar3_s2k(psw, salt): """String-to-key hash for RAR3. """ if not isinstance(psw, unicode): psw = psw.decode('utf8') seed = psw.encode('utf-16le') + salt iv = EMPTY h = sha1() for i in range(16): for j in range(0x4000): cnt = S_LONG.pack(i * 0x4000 + j) h.update(seed + cnt[:3]) if j == 0: iv += h.digest()[19:20] key_be = h.digest()[:16] key_le = pack("LLLL", key_be)) return key_le, iv def rar3_decompress(vers, meth, data, declen=0, flags=0, crc=0, psw=None, salt=None): """Decompress blob of compressed data. Used for data with non-standard header - eg. comments. """ # already uncompressed? if meth == RAR_M0 and (flags & RAR_FILE_PASSWORD) == 0: return data # take only necessary flags flags = flags & (RAR_FILE_PASSWORD | RAR_FILE_SALT | RAR_FILE_DICTMASK) flags |= RAR_LONG_BLOCK # file header fname = b'data' date = 0 mode = 0x20 fhdr = S_FILE_HDR.pack(len(data), declen, RAR_OS_MSDOS, crc, date, vers, meth, len(fname), mode) fhdr += fname if flags & RAR_FILE_SALT: if not salt: return EMPTY fhdr += salt # full header hlen = S_BLK_HDR.size + len(fhdr) hdr = S_BLK_HDR.pack(0, RAR_BLOCK_FILE, flags, hlen) + fhdr hcrc = rar_crc32(hdr[2:]) & 0xFFFF hdr = S_BLK_HDR.pack(hcrc, RAR_BLOCK_FILE, flags, hlen) + fhdr # archive main header mh = S_BLK_HDR.pack(0x90CF, RAR_BLOCK_MAIN, 0, 13) + ZERO * (2 + 4) # decompress via temp rar tmpfd, tmpname = mkstemp(suffix='.rar') tmpf = os.fdopen(tmpfd, "wb") try: tmpf.write(RAR_ID + mh + hdr + data) tmpf.close() cmd = [UNRAR_TOOL] + list(OPEN_ARGS) add_password_arg(cmd, psw, (flags & RAR_FILE_PASSWORD)) cmd.append(tmpname) p = custom_popen(cmd) return p.communicate()[0] finally: tmpf.close() os.unlink(tmpname) def to_datetime(t): """Convert 6-part time tuple into datetime object. """ if t is None: return None # extract values year, mon, day, h, m, s = t # assume the values are valid try: return datetime(year, mon, day, h, m, s) except ValueError: pass # sanitize invalid values mday = (0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) if mon < 1: mon = 1 if mon > 12: mon = 12 if day < 1: day = 1 if day > mday[mon]: day = mday[mon] if h > 23: h = 23 if m > 59: m = 59 if s > 59: s = 59 if mon == 2 and day == 29: try: return datetime(year, mon, day, h, m, s) except ValueError: day = 28 return datetime(year, mon, day, h, m, s) def parse_dos_time(stamp): """Parse standard 32-bit DOS timestamp. """ sec, stamp = stamp & 0x1F, stamp >> 5 mn, stamp = stamp & 0x3F, stamp >> 6 hr, stamp = stamp & 0x1F, stamp >> 5 day, stamp = stamp & 0x1F, stamp >> 5 mon, stamp = stamp & 0x0F, stamp >> 4 yr = (stamp & 0x7F) + 1980 return (yr, mon, day, hr, mn, sec * 2) def custom_popen(cmd): """Disconnect cmd from parent fds, read only from stdout. """ # needed for py2exe creationflags = 0 if sys.platform == 'win32': creationflags = 0x08000000 # CREATE_NO_WINDOW # run command try: p = Popen(cmd, bufsize=0, stdout=PIPE, stdin=PIPE, stderr=STDOUT, creationflags=creationflags) except OSError as ex: if ex.errno == errno.ENOENT: raise RarCannotExec("Unrar not installed? (rarfile.UNRAR_TOOL=%r)" % UNRAR_TOOL) raise return p def custom_check(cmd, ignore_retcode=False): """Run command, collect output, raise error if needed. """ p = custom_popen(cmd) out, _ = p.communicate() if p.returncode and not ignore_retcode: raise RarExecError("Check-run failed") return out def add_password_arg(cmd, psw, ___required=False): """Append password switch to commandline. """ if UNRAR_TOOL == ALT_TOOL: return if psw is not None: cmd.append('-p' + psw) else: cmd.append('-p-') def check_returncode(p, out): """Raise exception according to unrar exit code. """ code = p.returncode if code == 0: return # map return code to exception class, codes from rar.txt errmap = [None, RarWarning, RarFatalError, RarCRCError, RarLockedArchiveError, # 1..4 RarWriteError, RarOpenError, RarUserError, RarMemoryError, # 5..8 RarCreateError, RarNoFilesError, RarWrongPassword] # 9..11 if UNRAR_TOOL == ALT_TOOL: errmap = [None] if code > 0 and code < len(errmap): exc = errmap[code] elif code == 255: exc = RarUserBreak elif code < 0: exc = RarSignalExit else: exc = RarUnknownError # format message if out: msg = "%s [%d]: %s" % (exc.__doc__, p.returncode, out) else: msg = "%s [%d]" % (exc.__doc__, p.returncode) raise exc(msg) def hmac_sha256(key, data): """HMAC-SHA256""" return HMAC(key, data, sha256).digest() def membuf_tempfile(memfile): memfile.seek(0, 0) tmpfd, tmpname = mkstemp(suffix='.rar') tmpf = os.fdopen(tmpfd, "wb") try: while True: buf = memfile.read(BSIZE) if not buf: break tmpf.write(buf) tmpf.close() except: tmpf.close() os.unlink(tmpname) raise return tmpname class XTempFile(object): __slots__ = ('_tmpfile', '_filename') def __init__(self, rarfile): if is_filelike(rarfile): self._tmpfile = membuf_tempfile(rarfile) self._filename = self._tmpfile else: self._tmpfile = None self._filename = rarfile def __enter__(self): return self._filename def __exit__(self, exc_type, exc_value, tb): if self._tmpfile: try: os.unlink(self._tmpfile) except OSError: pass self._tmpfile = None SABnzbd-2.3.2/sabnzbd/utils/rsslib.py0000644000000000000000000002570013217005257015570 0ustar 00000000000000#"""RSS 2.0 Generator # #This library encapsulates the generation of an RSS (2.0) feed # # #You may freely use this code in any way you can think of. #""" import xml.sax.saxutils #------------------------------------------------------------------------------ def encode_for_xml(unicode_data, encoding='ascii'): """ Encode unicode_data for use as XML or HTML, with characters outside of the encoding converted to XML numeric character references. """ try: return unicode_data.encode(encoding, 'xmlcharrefreplace') except ValueError: # ValueError is raised if there are unencodable chars in the # data and the 'xmlcharrefreplace' error handler is not found. # Pre-2.3 Python doesn't support the 'xmlcharrefreplace' error # handler, so we'll emulate it. return _xmlcharref_encode(unicode_data, encoding) def _xmlcharref_encode(unicode_data, encoding): """Emulate Python 2.3's 'xmlcharrefreplace' encoding error handler.""" chars = [] # Step through the unicode_data string one character at a time in # order to catch unencodable characters: for char in unicode_data: try: chars.append(char.encode(encoding, 'strict')) except UnicodeError: chars.append('&#%i;' % ord(char)) return ''.join(chars) class RSS: # """ # RSS # # This class encapsulates the creation of an RSS 2.0 feed # # The RSS2.0 spec can be found here: # http://blogs.law.harvard.edu/tech/rss # # # RSS validator : http://rss.scripting.com # # # The generation of an RSS feed is simple, the following is a # sample: # from rsslib import RSS, Item, Namespace # rss = RSS() # rss.channel.link = "http://channel.com" # rss.channel.title = "my channel title" # rss.channel.description = "my channel description" # # ns = Namespace( "foobar", "http://foobar.baz" ) # rss.channel.namespaces.append( ns ) # # item = Item() # item.link = "http://link.com" # item.description = "my link description" # item.title ="my item title" # item.nsItems[ns.name + ":foo"] = "bar" # rss.channel.items.append( item ) # # item = Item() # item.link = "http://link2.com" # item.description = "my link2 description" # item.title ="my item2 title" # item.nsItems[ns.name +":foo"] = "foo bar baz" # rss.channel.items.append( item ) # # print rss.write() # # output: # # # # my channel title # http://channel.com # my channel description # # my item title # http://link.com # my link description # bar # # # my item2 title # http://link2.com # my link2 description # foo bar baz # # # # # # author: cmallory /a t/ berserk /dot/ o r g # """ def __init__(self): self.channel = Channel() self.version = "2.0" self.contents = None # if __name__ == "__main__" : # from rsslib import RSS, Item, Namespace # rss = RSS() # rss.channel.link = "http://channel.com" # rss.channel.title = "my channel title" # rss.channel.description = "my channel description" # # ns = Namespace( "foobar", "http://foobar.baz" ) # rss.addNamespace( ns ) # # item = Item() # item.link = "http://link.com" # item.description = "my link description" # item.title ="my item title" # # item.enclosure.url = "http://enclosure.url.com" # item.enclosure.length = 12345 # item.enclosure.type = "audio/mpeg" # # item.nsItems[ns.name + ":foo"] = "bar" # rss.addItem( item ) # # item = Item() # item.link = "http://link2.com" # item.description = "my link2 description" # item.title ="my item2 title" # item.nsItems[ns.name +":foo"] = "foo bar baz" # rss.addItem( item ) # # print rss.write() #Write out the rss document def write( self ): self.contents = "\n" #contents += "\n" self.contents += " element def generateChannel( self ): contents = "" if ( self.channel.initialized() ): contents += "\n" contents += self.optionalWrite("title", self.channel.title ); contents += self.optionalWrite("link", self.channel.link ); contents += self.optionalWrite("description", self.channel.description ); contents += self.optionalWrite("language", self.channel.language ); contents += self.optionalWrite("copyright", self.channel.copyright ); contents += self.optionalWrite("category", self.channel.category ); contents += self.optionalWrite("managingEditor", self.channel.managingEditor ); contents += self.optionalWrite("webMaster", self.channel.webMaster ); contents += self.optionalWrite("pubDate", self.channel.pubDate ); contents += self.optionalWrite("lastBuildDate", self.channel.lastBuildDate ); contents += self.optionalWrite("docs", self.channel.docs ); contents += self.optionalWrite("cloud", self.channel.cloud ); contents += self.optionalWrite("ttl", self.channel.ttl ); contents += self.optionalWrite("generator", self.channel.generator ); contents += self.optionalWrite("image", self.channel.image ); contents += self.optionalWrite("rating", self.channel.rating ); contents += self.optionalWrite("textInput", self.channel.textInput ); contents += self.optionalWrite("skipHours", self.channel.skipHours ); contents += self.optionalWrite("skipDays", self.channel.skipDays ); contents += "\n" + self.generateItems() + "\n" else : contents = "[Channel not properly initialized. " contents +="A required field is not set.(title/link/description]" return contents #Generates all items within a channel def generateItems( self ): c = "" for i in self.channel.items : c += "" c += self.optionalWrite("title", i.title); c += self.optionalWrite("link", i.link ); c += self.optionalWrite("description", i.description); c += self.optionalWrite("author", i.author ); c += self.optionalWrite("pubDate", str(i.pubDate) ) c += self.optionalWrite("category", i.category ) c += self.optionalWrite("comments", i.comments ) c += self.optionalWrite("guid", i.guid ) c += self.optionalWrite("source", i.source ) if ( i.enclosure.url != "" ): c+= "\n" for k in i.nsItems.keys(): c += self.optionalWrite( k , i.nsItems[ k ] ) c += "\n\n" return c def addNamespace( self, ns ): if ( self.channel.namespaces is not None ): self.channel.namespaces.append( ns ) def addItem( self, item ): if ( self.channel is not None): self.channel.items.append( item ) def optionalWrite( self, key, val ): if ( val is not None and val != "" ): return "<" + key + ">" + encode_for_xml(xml.sax.saxutils.escape(val)) + "\n" else: return "" #Namespace class Namespace: def __init__( self, name, url ): self.url = url self.name = name class Channel: # """ # Channel # # (http://blogs.law.harvard.edu/tech/rss) # # This object represents an RSS channel (as of ver2.0) # """ def __init__( self ): # # Required Fields # self.title= None self.link= None self.description= None # # Optional Fields # self.language = "" self.copyright = "" self.managingEditor = "" self.webMaster = "" self.pubDate = "" self.lastBuildDate = "" self.category = "" self.generator = "" self.docs = "" self.cloud = "" self.ttl = "" self.image = "" self.rating = "" self.textInput = "" self.skipHours = "" self.skipDays = "" self.items = [] self.namespaces = [] def initialized( self ): return self.title is not None and self.link is not None and self.description is not None class Item: # """ # Item # # http://blogs.law.harvard.edu/tech/rss#hrelementsOfLtitemgt # # A channel may contain any number of <item>s. An item may # represent a "story" -- much like a story in a newspaper or magazine; # if so its description is a synopsis of the story, and the link # points to the full story. An item may also be complete in itself, # if so, the description contains the text (entity-encoded HTML is # allowed; see examples), and the link and title may be omitted. # All elements of an item are optional, however at least one of # title or description must be present. # """ def __init__( self ): self.title = "" self.link = "" self.description = "" self.author = "" self.category = "" self.comments = "" self.enclosure = "" self.guid = "" self.pubDate = "" self.source = "" self.enclosure = Enclosure() self.nsItems = {} class Enclosure: # """ # Enclosure # # sub-element of # # is an optional sub-element of . # # It has three required attributes: # # url: says where the enclosure is located, # length: says how big it is in bytes, and # type: says what its type is, a standard MIME type. # # The url must be an http url. # # Example: # # """ def __init__(self): self.url = "" self.length = 0 self.type = "" SABnzbd-2.3.2/sabnzbd/utils/servertests.py0000644000000000000000000001210213217005257016653 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.utils.servertests - Debugging server connections. Currently only NNTP server tests are done. """ import socket import sys import select from sabnzbd.newswrapper import NewsWrapper from sabnzbd.downloader import Server, clues_login, clues_too_many, nntp_to_msg from sabnzbd.config import get_servers from sabnzbd.misc import int_conv def test_nntp_server_dict(kwargs): # Grab the host/port/user/pass/connections/ssl host = kwargs.get('host', '').strip() if not host: return False, T('The hostname is not set.') username = kwargs.get('username', '').strip() password = kwargs.get('password', '').strip() server = kwargs.get('server', '').strip() connections = int_conv(kwargs.get('connections', 0)) if not connections: return False, T('There are no connections set. Please set at least one connection.') ssl = int_conv(kwargs.get('ssl', 0)) ssl_verify = int_conv(kwargs.get('ssl_verify', 1)) port = int_conv(kwargs.get('port', 0)) if not port: if ssl: port = 563 else: port = 119 return test_nntp_server(host, port, server, username=username, password=password, ssl=ssl, ssl_verify=ssl_verify) def test_nntp_server(host, port, server=None, username=None, password=None, ssl=None, ssl_verify=1): """ Will connect (blocking) to the nttp server and report back any errors """ timeout = 4.0 if '*' in password and not password.strip('*'): # If the password is masked, try retrieving it from the config if not server: servers = get_servers() got_pass = False for server in servers: if host in servers[server].host(): srv = servers[server] password = srv.password() got_pass = True else: srv = get_servers().get(server) if srv: password = srv.password() got_pass = True if not got_pass: return False, T('Password masked in ******, please re-enter') try: s = Server(-1, '', host, port, timeout, 0, 0, ssl, ssl_verify, False, username, password) except: return False, T('Invalid server details') try: nw = NewsWrapper(s, -1, block=True) nw.init_connect(None) while not nw.connected: nw.clear_data() nw.recv_chunk(block=True) #more ssl related: handle 1/n-1 splitting to prevent Rizzo/Duong-Beast read_sockets, _, _ = select.select([nw.nntp.sock], [], [], 0.1) if read_sockets: nw.recv_chunk(block=True) nw.finish_connect(nw.status_code) except socket.timeout, e: if port != 119 and not ssl: return False, T('Timed out: Try enabling SSL or connecting on a different port.') else: return False, T('Timed out') except socket.error, e: # Trying SSL on non-SSL port? if 'unknown protocol' in str(e).lower(): return False, T('Unknown SSL protocol: Try disabling SSL or connecting on a different port.') return False, unicode(e) except TypeError, e: return False, T('Invalid server address.') except IndexError: # No data was received in recv_chunk() call return False, T('Server quit during login sequence.') except: return False, unicode(sys.exc_info()[1]) if not username or not password: nw.nntp.sock.sendall('ARTICLE \r\n') try: nw.clear_data() nw.recv_chunk(block=True) except: return False, unicode(sys.exc_info()[1]) if nw.status_code == '480': return False, T('Server requires username and password.') elif nw.status_code == '100' or nw.status_code.startswith(('2', '4')): return True, T('Connection Successful!') elif nw.status_code == '502' or clues_login(nntp_to_msg(nw.data)): return False, T('Authentication failed, check username/password.') elif clues_too_many(nw.lines[0]): return False, T('Too many connections, please pause downloading or try again later') else: return False, T('Could not determine connection result (%s)') % nntp_to_msg(nw.data) # Close the connection nw.terminate(quit=True) SABnzbd-2.3.2/sabnzbd/utils/systrayiconthread.py0000644000000000000000000002614513217005257020055 0ustar 00000000000000#!/usr/bin/env python # based on SysTrayIcon.py by Simon Brunning - simon@brunningonline.net # http://www.brunningonline.net/simon/blog/archives/001835.html # http://www.brunningonline.net/simon/blog/archives/SysTrayIcon.py.html # modified on 2011-10-04 by Jan Schejbal to support threading and preload icons # override doUpdates to perform actions inside the icon thread # override click to perform actions when left-clicking the icon import os import pywintypes import win32api import win32con import win32gui_struct import timer try: import winxpgui as win32gui except ImportError: import win32gui from threading import Thread from time import sleep class SysTrayIconThread(Thread): QUIT = 'QUIT' SPECIAL_ACTIONS = [QUIT] FIRST_ID = 1023 terminate = False def __init__(self, icon, hover_text, menu_options, on_quit=None, default_menu_index=None, window_class_name=None,): Thread.__init__(self) self.icon = icon self.icons = {} self.hover_text = hover_text self.on_quit = on_quit # menu_options = menu_options + (('Quit', None, self.QUIT),) self._next_action_id = self.FIRST_ID self.menu_actions_by_id = set() self.menu_options = self._add_ids_to_menu_options(list(menu_options)) self.menu_actions_by_id = dict(self.menu_actions_by_id) del self._next_action_id self.click_timer = None self.default_menu_index = (default_menu_index or 0) self.window_class_name = window_class_name or "SysTrayIconPy" self.start() def initialize(self): message_map = {win32gui.RegisterWindowMessage("TaskbarCreated"): self.restart, win32con.WM_DESTROY: self.destroy, win32con.WM_COMMAND: self.command, win32con.WM_USER + 20: self.notify, } # Register the Window class. window_class = win32gui.WNDCLASS() hinst = window_class.hInstance = win32gui.GetModuleHandle(None) window_class.lpszClassName = self.window_class_name window_class.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW window_class.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW) window_class.hbrBackground = win32con.COLOR_WINDOW window_class.lpfnWndProc = message_map # could also specify a wndproc. classAtom = win32gui.RegisterClass(window_class) # Create the Window. style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU self.hwnd = win32gui.CreateWindow(classAtom, self.window_class_name, style, 0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, 0, 0, hinst, None) win32gui.UpdateWindow(self.hwnd) self.notify_id = None self.refresh_icon() def run(self): self.initialize() while not self.terminate: win32gui.PumpWaitingMessages() self.doUpdates() sleep(0.100) win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, (self.hwnd, 0)) # Override this def doUpdates(self): pass # Notification def sendnotification(self, title, msg): hicon = self.get_icon(self.icon) win32gui.Shell_NotifyIcon(win32gui.NIM_MODIFY, (self.hwnd, 0, win32gui.NIF_INFO, win32con.WM_USER+20, hicon, "Balloon tooltip", msg, 200, title)) def _add_ids_to_menu_options(self, menu_options): result = [] for menu_option in menu_options: option_text, option_icon, option_action = menu_option if callable(option_action) or option_action in self.SPECIAL_ACTIONS: self.menu_actions_by_id.add((self._next_action_id, option_action)) result.append(menu_option + (self._next_action_id,)) elif non_string_iterable(option_action): result.append((option_text, option_icon, self._add_ids_to_menu_options(option_action), self._next_action_id)) else: print 'Unknown item', option_text, option_icon, option_action self._next_action_id += 1 return result def get_icon(self, path): hicon = self.icons.get(path) if hicon != None: return hicon # Try and find a custom icon hinst = win32gui.GetModuleHandle(None) if os.path.isfile(path): icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE hicon = win32gui.LoadImage(hinst, path, win32con.IMAGE_ICON, 0, 0, icon_flags) else: print "Can't find icon file - using default." hicon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION) self.icons[path] = hicon return hicon def refresh_icon(self): hicon = self.get_icon(self.icon) if self.notify_id: message = win32gui.NIM_MODIFY else: message = win32gui.NIM_ADD self.notify_id = (self.hwnd, 0, win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP, win32con.WM_USER + 20, hicon, self.hover_text) try: win32gui.Shell_NotifyIcon(message, self.notify_id) except: # Timeouts can occur after system comes out of standby/hibernate pass def restart(self, hwnd, msg, wparam, lparam): self.refresh_icon() def destroy(self, hwnd, msg, wparam, lparam): if self.on_quit: self.on_quit(self) nid = (self.hwnd, 0) win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, nid) win32gui.PostQuitMessage(0) # Terminate the app. def notify(self, hwnd, msg, wparam, lparam): # Double click is actually 1 single click followed # by a double-click event, no way to differentiate # So we need a timed callback to cancel if lparam == win32con.WM_LBUTTONDBLCLK: self.execute_menu_option(self.default_menu_index + self.FIRST_ID) self.stop_click_timer() elif lparam == win32con.WM_RBUTTONUP: self.show_menu() elif lparam == win32con.WM_LBUTTONDOWN: # Wrapper of win32api, timeout is in ms # We need to wait at least untill what user has defined as double click self.stop_click_timer() self.click_timer = timer.set_timer(win32gui.GetDoubleClickTime(), self.click) return True def show_menu(self): menu = win32gui.CreatePopupMenu() self.create_menu(menu, self.menu_options) #win32gui.SetMenuDefaultItem(menu, 1000, 0) try: pos = win32gui.GetCursorPos() # See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/menus_0hdi.asp win32gui.SetForegroundWindow(self.hwnd) win32gui.TrackPopupMenu(menu, win32con.TPM_LEFTALIGN, pos[0], pos[1], 0, self.hwnd, None) win32gui.PostMessage(self.hwnd, win32con.WM_NULL, 0, 0) except pywintypes.error: # Weird PyWin/win32gui bug, just ignore it for now pass # Override this for left-click action # Need to call the stop-timer in that function! def click(self, *args): pass def stop_click_timer(self): # Stop the timer if self.click_timer: timer.kill_timer(self.click_timer) self.click_timer = None def create_menu(self, menu, menu_options): for option_text, option_icon, option_action, option_id in menu_options[::-1]: if option_icon: option_icon = self.prep_menu_icon(option_icon) if option_id in self.menu_actions_by_id: item, extras = win32gui_struct.PackMENUITEMINFO(text=option_text, hbmpItem=option_icon, wID=option_id) win32gui.InsertMenuItem(menu, 0, 1, item) else: submenu = win32gui.CreatePopupMenu() self.create_menu(submenu, option_action) item, extras = win32gui_struct.PackMENUITEMINFO(text=option_text, hbmpItem=option_icon, hSubMenu=submenu) win32gui.InsertMenuItem(menu, 0, 1, item) def prep_menu_icon(self, icon): # First load the icon. ico_x = win32api.GetSystemMetrics(win32con.SM_CXSMICON) ico_y = win32api.GetSystemMetrics(win32con.SM_CYSMICON) hicon = win32gui.LoadImage(0, icon, win32con.IMAGE_ICON, ico_x, ico_y, win32con.LR_LOADFROMFILE) hdcBitmap = win32gui.CreateCompatibleDC(0) hdcScreen = win32gui.GetDC(0) hbm = win32gui.CreateCompatibleBitmap(hdcScreen, ico_x, ico_y) hbmOld = win32gui.SelectObject(hdcBitmap, hbm) # Fill the background. brush = win32gui.GetSysColorBrush(win32con.COLOR_MENU) win32gui.FillRect(hdcBitmap, (0, 0, 16, 16), brush) # unclear if brush needs to be feed. Best clue I can find is: # "GetSysColorBrush returns a cached brush instead of allocating a new # one." - implies no DeleteObject # draw the icon win32gui.DrawIconEx(hdcBitmap, 0, 0, hicon, ico_x, ico_y, 0, 0, win32con.DI_NORMAL) win32gui.SelectObject(hdcBitmap, hbmOld) win32gui.DeleteDC(hdcBitmap) return hbm def command(self, hwnd, msg, wparam, lparam): id = win32gui.LOWORD(wparam) self.execute_menu_option(id) def execute_menu_option(self, id): menu_action = self.menu_actions_by_id[id] if menu_action == self.QUIT: win32gui.DestroyWindow(self.hwnd) else: menu_action(self) def non_string_iterable(obj): try: iter(obj) except TypeError: return False else: return not isinstance(obj, basestring) SABnzbd-2.3.2/sabnzbd/utils/upload.py0000644000000000000000000000474213217005257015561 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2009-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.utils.upload - File association functions for adding nzb files to sabnzbd """ import urllib import logging import os from sabnzbd.encoding import unicoder import sabnzbd.cfg as cfg from sabnzbd.misc import get_ext, get_filename, get_from_url import sabnzbd.newsunpack from sabnzbd.constants import VALID_ARCHIVES from sabnzbd.dirscanner import ProcessArchiveFile, ProcessSingleFile def upload_file(url, fp): """ Function for uploading nzbs to a running sabnzbd instance """ try: fp = unicoder(fp).encode('utf-8') fp = urllib.quote_plus(fp) url = '%s&mode=addlocalfile&name=%s' % (url, fp) # Add local apikey if it wasn't already in the registered URL apikey = cfg.api_key() if apikey and 'apikey' not in url: url = '%s&apikey=%s' % (url, apikey) if 'apikey' not in url: # Use alternative login method username = cfg.username() password = cfg.password() if username and password: url = '%s&ma_username=%s&ma_password=%s' % (url, username, password) get_from_url(url) except: logging.error("Failed to upload file: %s", fp) logging.info("Traceback: ", exc_info=True) def add_local(f): """ Function for easily adding nzb/zip/rar/nzb.gz to sabnzbd """ if os.path.exists(f): fn = get_filename(f) if fn: if get_ext(fn) in VALID_ARCHIVES: ProcessArchiveFile(fn, f, keep=True) elif get_ext(fn) in ('.nzb', '.gz', '.bz2'): ProcessSingleFile(fn, f, keep=True) else: logging.error("Filename not found: %s", f) else: logging.error("File not found: %s", f) SABnzbd-2.3.2/sabnzbd/utils/__init__.py0000644000000000000000000000135013217005257016024 0ustar 00000000000000# __init__.py """ Monkey patches cryptography's backend detection. Objective: support py2exe/pyinstaller freezing. https://github.com/pyca/cryptography/issues/2039#issuecomment-115432291 Required for RARfile.py and CertGen.py! """ try: from cryptography.hazmat import backends try: from cryptography.hazmat.backends.commoncrypto.backend import backend as backend_cc except ImportError: backend_cc = None try: from cryptography.hazmat.backends.openssl.backend import backend as backend_ossl except ImportError: backend_ossl = None backends._available_backends_list = [ backend for backend in (backend_cc, backend_ossl) if backend is not None ] except: # No crypto passSABnzbd-2.3.2/scripts/Deobfuscate.py0000644000000000000000000001336313217005257015424 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ Deobfuscation post-processing script: Will check in the completed job folder if maybe there are par2 files, for example "rename.par2", and use those to rename the files. If there is no "rename.par2" available, it will rename the largest file to the job-name in the queue. NOTES: 1) To use this script you need Python installed on your system and select "Add to path" during its installation. Select this folder in Config > Folders > Scripts Folder and select this script for each job you want it sued for, or link it to a category in Config > Categories. 2) Beware that files on the 'Cleanup List' are removed before scripts are called and if any of them happen to be required by the found par2 file, it will fail. 3) If there are multiple larger (>40MB) files, then the script will not rename anything, since it could be a multi-pack. 4) If you want to modify this script, make sure to copy it out of this directory, or it will be overwritten when SABnzbd is updated. 5) Feedback or bugs in this script can be reported in on our forum: https://forums.sabnzbd.org/viewforum.php?f=9 """ import os import sys import time import fnmatch import subprocess # Files to exclude and minimal file size for renaming EXCLUDED_FILE_EXTS = ('.vob', '.bin') MIN_FILE_SIZE = 40*1024*1024 # Are we being called from SABnzbd? if not os.environ.get('SAB_VERSION'): print "This script needs to be called from SABnzbd as post-processing script." sys.exit(1) def print_splitter(): """ Simple helper function """ print '\n------------------------\n' # Windows or others? par2_command = os.environ['SAB_PAR2_COMMAND'] if os.environ['SAB_MULTIPAR_COMMAND']: par2_command = os.environ['SAB_MULTIPAR_COMMAND'] # Diagnostic info print_splitter() print 'SABnzbd version: ', os.environ['SAB_VERSION'] print 'Job location: ', os.environ['SAB_COMPLETE_DIR'] print 'Par2-command: ', par2_command print_splitter() # Search for par2 files matches = [] for root, dirnames, filenames in os.walk(os.environ['SAB_COMPLETE_DIR']): for filename in fnmatch.filter(filenames, '*.par2'): matches.append(os.path.join(root, filename)) print 'Found file:', os.path.join(root, filename) # Found any par2 files we can use? run_renamer = True if not matches: print "No par2 files found to process." # Run par2 from SABnzbd on them for par2_file in matches: # Build command, make it check the whole directory wildcard = os.path.join(os.environ['SAB_COMPLETE_DIR'], '*') command = [str(par2_command), 'r', par2_file, wildcard] # Start command print_splitter() print 'Starting command: ', repr(command) try: result = subprocess.check_output(command) except subprocess.CalledProcessError as e: # Multipar also gives non-zero in case of succes result = e.output # Show output print_splitter() print result print_splitter() # Last status-line for the History # Check if the magic words are there if 'Repaired successfully' in result or 'All files are correct' in result or \ 'Repair complete' in result or 'All Files Complete' in result or 'PAR File(s) Incomplete' in result: print 'Recursive repair/verify finished.' run_renamer = False else: print 'Recursive repair/verify did not complete!' # No matches? Then we try to rename the largest file to the job-name if run_renamer: print_splitter() print 'Trying to see if there are large files to rename' print_splitter() # If there are more larger files, we don't rename largest_file = None for root, dirnames, filenames in os.walk(os.environ['SAB_COMPLETE_DIR']): for filename in filenames: full_path = os.path.join(root, filename) file_size = os.path.getsize(full_path) # Do we count this file? if file_size > MIN_FILE_SIZE and os.path.splitext(filename)[1].lower() not in EXCLUDED_FILE_EXTS: # Did we already found one? if largest_file: print 'Found:', largest_file print 'Found:', full_path print_splitter() print 'Found multiple larger files, aborting.' largest_file = None break largest_file = full_path # Found something large enough? if largest_file: # We don't need to do any cleaning of dir-names # since SABnzbd already did that! new_name = '%s%s' % (os.path.join(os.environ['SAB_COMPLETE_DIR'], os.environ['SAB_FINAL_NAME']), os.path.splitext(largest_file)[1].lower()) print 'Renaming %s to %s' % (largest_file, new_name) # With retries for Windows for r in range(3): try: os.rename(largest_file, new_name) print 'Renaming done!' break except: time.sleep(1) else: print 'No par2 files or large files found' # Always exit with succes-code sys.exit(0) SABnzbd-2.3.2/scripts/Sample-PostProc.cmd0000644000000000000000000000071613217005257016301 0ustar 00000000000000@echo off rem Example of a post processing script for SABnzbd echo. echo Running in directory "%~d0%~p0" echo. echo The first parameter (result-dir) = %1 echo The second parameter (nzb-name) = %2 echo The third parameter (nice name) = %3 echo The fourth parameter (newzbin #) = %4 echo The fifth parameter (category) = %5 echo The sixth parameter (group) = %6 echo The seventh parameter (status) = %7 echo The eight parameter (failure_url)= %8 echo. SABnzbd-2.3.2/scripts/Sample-PostProc.py0000644000000000000000000000265113217005257016166 0ustar 00000000000000#!/usr/bin/env python # Example Post-Processing Script for SABnzbd (2.3.1 and higher), written in Python. # For Linux, MacOS, Windows and any other platform with Python # See https://sabnzbd.org/wiki/scripts/post-processing-scripts for details # # Example test run on Linux: # env SAB_VERSION=X.Y SAB_AVG_BPS=666 python ./Sample-PostProc.py somedir222 nzbname CleanJobName123 Index12 Cat88 MyGroup PP0 https://example.com/ import sys, os # Raw parsing of input parameters en SABnzbd environment variables counter = 0 print "\nINPUT from argv:\n" for item in sys.argv: print "Argument", counter, ":", item counter += 1 print "\nINPUT from environment variables (only SAB specifics):\n" for item in os.environ: if item.find("SAB_") == 0: print item, os.environ[item] # More intelligent parsing: try: (scriptname,directory,orgnzbname,jobname,reportnumber,category,group,postprocstatus,url) = sys.argv except: print "No SAB compliant number of commandline parameters found (should be 8):", len(sys.argv)-1 sys.exit(1) # non-zero return code # Some examples: print "\nExamples of some specific values:\n" print "jobname is", jobname try: sabversion = os.environ['SAB_VERSION'] print "sabversion is", sabversion except: pass ''' your code here ''' # We're done: print "\nScript done. All OK." # the last line will appear in the SABnzb History GUI sys.exit(0) # The result code towards SABnzbd SABnzbd-2.3.2/scripts/Sample-PostProc.sh0000755000000000000000000000073213217005257016151 0ustar 00000000000000#!/bin/sh # Example of a post processing script for SABnzbd echo echo Started as $0 echo echo "The first parameter (result-dir) =" "$1" echo "The second parameter (nzb-name) =" "$2" echo "The third parameter (nice name) =" "$3" echo "The fourth parameter (newzbin-id) =" "$4" echo "The fifth parameter (category) =" "$5" echo "The sixth parameter (group) =" "$6" echo "The seventh parameter (status) =" "$7" echo "The eight parameter (failure_url) =" "$8" SABnzbd-2.3.2/six/__init__.py0000644000000000000000000007425013217005257014055 0ustar 00000000000000# Copyright (c) 2010-2017 Benjamin Peterson # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """Utilities for writing code that runs on Python 2 and 3""" from __future__ import absolute_import import functools import itertools import operator import sys import types __author__ = "Benjamin Peterson " __version__ = "1.11.0" # Useful for very coarse version differentiation. PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] == 3 PY34 = sys.version_info[0:2] >= (3, 4) if PY3: string_types = str, integer_types = int, class_types = type, text_type = str binary_type = bytes MAXSIZE = sys.maxsize else: string_types = basestring, integer_types = (int, long) class_types = (type, types.ClassType) text_type = unicode binary_type = str if sys.platform.startswith("java"): # Jython always uses 32 bits. MAXSIZE = int((1 << 31) - 1) else: # It's possible to have sizeof(long) != sizeof(Py_ssize_t). class X(object): def __len__(self): return 1 << 31 try: len(X()) except OverflowError: # 32-bit MAXSIZE = int((1 << 31) - 1) else: # 64-bit MAXSIZE = int((1 << 63) - 1) del X def _add_doc(func, doc): """Add documentation to a function.""" func.__doc__ = doc def _import_module(name): """Import module, returning the module after the last dot.""" __import__(name) return sys.modules[name] class _LazyDescr(object): def __init__(self, name): self.name = name def __get__(self, obj, tp): result = self._resolve() setattr(obj, self.name, result) # Invokes __set__. try: # This is a bit ugly, but it avoids running this again by # removing this descriptor. delattr(obj.__class__, self.name) except AttributeError: pass return result class MovedModule(_LazyDescr): def __init__(self, name, old, new=None): super(MovedModule, self).__init__(name) if PY3: if new is None: new = name self.mod = new else: self.mod = old def _resolve(self): return _import_module(self.mod) def __getattr__(self, attr): _module = self._resolve() value = getattr(_module, attr) setattr(self, attr, value) return value class _LazyModule(types.ModuleType): def __init__(self, name): super(_LazyModule, self).__init__(name) self.__doc__ = self.__class__.__doc__ def __dir__(self): attrs = ["__doc__", "__name__"] attrs += [attr.name for attr in self._moved_attributes] return attrs # Subclasses should override this _moved_attributes = [] class MovedAttribute(_LazyDescr): def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): super(MovedAttribute, self).__init__(name) if PY3: if new_mod is None: new_mod = name self.mod = new_mod if new_attr is None: if old_attr is None: new_attr = name else: new_attr = old_attr self.attr = new_attr else: self.mod = old_mod if old_attr is None: old_attr = name self.attr = old_attr def _resolve(self): module = _import_module(self.mod) return getattr(module, self.attr) class _SixMetaPathImporter(object): """ A meta path importer to import six.moves and its submodules. This class implements a PEP302 finder and loader. It should be compatible with Python 2.5 and all existing versions of Python3 """ def __init__(self, six_module_name): self.name = six_module_name self.known_modules = {} def _add_module(self, mod, *fullnames): for fullname in fullnames: self.known_modules[self.name + "." + fullname] = mod def _get_module(self, fullname): return self.known_modules[self.name + "." + fullname] def find_module(self, fullname, path=None): if fullname in self.known_modules: return self return None def __get_module(self, fullname): try: return self.known_modules[fullname] except KeyError: raise ImportError("This loader does not know module " + fullname) def load_module(self, fullname): try: # in case of a reload return sys.modules[fullname] except KeyError: pass mod = self.__get_module(fullname) if isinstance(mod, MovedModule): mod = mod._resolve() else: mod.__loader__ = self sys.modules[fullname] = mod return mod def is_package(self, fullname): """ Return true, if the named module is a package. We need this method to get correct spec objects with Python 3.4 (see PEP451) """ return hasattr(self.__get_module(fullname), "__path__") def get_code(self, fullname): """Return None Required, if is_package is implemented""" self.__get_module(fullname) # eventually raises ImportError return None get_source = get_code # same as get_code _importer = _SixMetaPathImporter(__name__) class _MovedItems(_LazyModule): """Lazy loading of moved objects""" __path__ = [] # mark as package _moved_attributes = [ MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), MovedAttribute("intern", "__builtin__", "sys"), MovedAttribute("map", "itertools", "builtins", "imap", "map"), MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), MovedAttribute("getoutput", "commands", "subprocess"), MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), MovedAttribute("reduce", "__builtin__", "functools"), MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), MovedAttribute("StringIO", "StringIO", "io"), MovedAttribute("UserDict", "UserDict", "collections"), MovedAttribute("UserList", "UserList", "collections"), MovedAttribute("UserString", "UserString", "collections"), MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), MovedModule("builtins", "__builtin__"), MovedModule("configparser", "ConfigParser"), MovedModule("copyreg", "copy_reg"), MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), MovedModule("http_cookies", "Cookie", "http.cookies"), MovedModule("html_entities", "htmlentitydefs", "html.entities"), MovedModule("html_parser", "HTMLParser", "html.parser"), MovedModule("http_client", "httplib", "http.client"), MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), MovedModule("cPickle", "cPickle", "pickle"), MovedModule("queue", "Queue"), MovedModule("reprlib", "repr"), MovedModule("socketserver", "SocketServer"), MovedModule("_thread", "thread", "_thread"), MovedModule("tkinter", "Tkinter"), MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), MovedModule("tkinter_tix", "Tix", "tkinter.tix"), MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"), MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"), MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), MovedModule("tkinter_font", "tkFont", "tkinter.font"), MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), ] # Add windows specific modules. if sys.platform == "win32": _moved_attributes += [ MovedModule("winreg", "_winreg"), ] for attr in _moved_attributes: setattr(_MovedItems, attr.name, attr) if isinstance(attr, MovedModule): _importer._add_module(attr, "moves." + attr.name) del attr _MovedItems._moved_attributes = _moved_attributes moves = _MovedItems(__name__ + ".moves") _importer._add_module(moves, "moves") class Module_six_moves_urllib_parse(_LazyModule): """Lazy loading of moved objects in six.moves.urllib_parse""" _urllib_parse_moved_attributes = [ MovedAttribute("ParseResult", "urlparse", "urllib.parse"), MovedAttribute("SplitResult", "urlparse", "urllib.parse"), MovedAttribute("parse_qs", "urlparse", "urllib.parse"), MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), MovedAttribute("urldefrag", "urlparse", "urllib.parse"), MovedAttribute("urljoin", "urlparse", "urllib.parse"), MovedAttribute("urlparse", "urlparse", "urllib.parse"), MovedAttribute("urlsplit", "urlparse", "urllib.parse"), MovedAttribute("urlunparse", "urlparse", "urllib.parse"), MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), MovedAttribute("quote", "urllib", "urllib.parse"), MovedAttribute("quote_plus", "urllib", "urllib.parse"), MovedAttribute("unquote", "urllib", "urllib.parse"), MovedAttribute("unquote_plus", "urllib", "urllib.parse"), MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), MovedAttribute("urlencode", "urllib", "urllib.parse"), MovedAttribute("splitquery", "urllib", "urllib.parse"), MovedAttribute("splittag", "urllib", "urllib.parse"), MovedAttribute("splituser", "urllib", "urllib.parse"), MovedAttribute("splitvalue", "urllib", "urllib.parse"), MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), MovedAttribute("uses_params", "urlparse", "urllib.parse"), MovedAttribute("uses_query", "urlparse", "urllib.parse"), MovedAttribute("uses_relative", "urlparse", "urllib.parse"), ] for attr in _urllib_parse_moved_attributes: setattr(Module_six_moves_urllib_parse, attr.name, attr) del attr Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes _importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), "moves.urllib_parse", "moves.urllib.parse") class Module_six_moves_urllib_error(_LazyModule): """Lazy loading of moved objects in six.moves.urllib_error""" _urllib_error_moved_attributes = [ MovedAttribute("URLError", "urllib2", "urllib.error"), MovedAttribute("HTTPError", "urllib2", "urllib.error"), MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), ] for attr in _urllib_error_moved_attributes: setattr(Module_six_moves_urllib_error, attr.name, attr) del attr Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes _importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), "moves.urllib_error", "moves.urllib.error") class Module_six_moves_urllib_request(_LazyModule): """Lazy loading of moved objects in six.moves.urllib_request""" _urllib_request_moved_attributes = [ MovedAttribute("urlopen", "urllib2", "urllib.request"), MovedAttribute("install_opener", "urllib2", "urllib.request"), MovedAttribute("build_opener", "urllib2", "urllib.request"), MovedAttribute("pathname2url", "urllib", "urllib.request"), MovedAttribute("url2pathname", "urllib", "urllib.request"), MovedAttribute("getproxies", "urllib", "urllib.request"), MovedAttribute("Request", "urllib2", "urllib.request"), MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), MovedAttribute("BaseHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), MovedAttribute("FileHandler", "urllib2", "urllib.request"), MovedAttribute("FTPHandler", "urllib2", "urllib.request"), MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), MovedAttribute("urlretrieve", "urllib", "urllib.request"), MovedAttribute("urlcleanup", "urllib", "urllib.request"), MovedAttribute("URLopener", "urllib", "urllib.request"), MovedAttribute("FancyURLopener", "urllib", "urllib.request"), MovedAttribute("proxy_bypass", "urllib", "urllib.request"), MovedAttribute("parse_http_list", "urllib2", "urllib.request"), MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), ] for attr in _urllib_request_moved_attributes: setattr(Module_six_moves_urllib_request, attr.name, attr) del attr Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes _importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), "moves.urllib_request", "moves.urllib.request") class Module_six_moves_urllib_response(_LazyModule): """Lazy loading of moved objects in six.moves.urllib_response""" _urllib_response_moved_attributes = [ MovedAttribute("addbase", "urllib", "urllib.response"), MovedAttribute("addclosehook", "urllib", "urllib.response"), MovedAttribute("addinfo", "urllib", "urllib.response"), MovedAttribute("addinfourl", "urllib", "urllib.response"), ] for attr in _urllib_response_moved_attributes: setattr(Module_six_moves_urllib_response, attr.name, attr) del attr Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes _importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), "moves.urllib_response", "moves.urllib.response") class Module_six_moves_urllib_robotparser(_LazyModule): """Lazy loading of moved objects in six.moves.urllib_robotparser""" _urllib_robotparser_moved_attributes = [ MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), ] for attr in _urllib_robotparser_moved_attributes: setattr(Module_six_moves_urllib_robotparser, attr.name, attr) del attr Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes _importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), "moves.urllib_robotparser", "moves.urllib.robotparser") class Module_six_moves_urllib(types.ModuleType): """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" __path__ = [] # mark as package parse = _importer._get_module("moves.urllib_parse") error = _importer._get_module("moves.urllib_error") request = _importer._get_module("moves.urllib_request") response = _importer._get_module("moves.urllib_response") robotparser = _importer._get_module("moves.urllib_robotparser") def __dir__(self): return ['parse', 'error', 'request', 'response', 'robotparser'] _importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), "moves.urllib") def add_move(move): """Add an item to six.moves.""" setattr(_MovedItems, move.name, move) def remove_move(name): """Remove item from six.moves.""" try: delattr(_MovedItems, name) except AttributeError: try: del moves.__dict__[name] except KeyError: raise AttributeError("no such move, %r" % (name,)) if PY3: _meth_func = "__func__" _meth_self = "__self__" _func_closure = "__closure__" _func_code = "__code__" _func_defaults = "__defaults__" _func_globals = "__globals__" else: _meth_func = "im_func" _meth_self = "im_self" _func_closure = "func_closure" _func_code = "func_code" _func_defaults = "func_defaults" _func_globals = "func_globals" try: advance_iterator = next except NameError: def advance_iterator(it): return it.next() next = advance_iterator try: callable = callable except NameError: def callable(obj): return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) if PY3: def get_unbound_function(unbound): return unbound create_bound_method = types.MethodType def create_unbound_method(func, cls): return func Iterator = object else: def get_unbound_function(unbound): return unbound.im_func def create_bound_method(func, obj): return types.MethodType(func, obj, obj.__class__) def create_unbound_method(func, cls): return types.MethodType(func, None, cls) class Iterator(object): def next(self): return type(self).__next__(self) callable = callable _add_doc(get_unbound_function, """Get the function out of a possibly unbound function""") get_method_function = operator.attrgetter(_meth_func) get_method_self = operator.attrgetter(_meth_self) get_function_closure = operator.attrgetter(_func_closure) get_function_code = operator.attrgetter(_func_code) get_function_defaults = operator.attrgetter(_func_defaults) get_function_globals = operator.attrgetter(_func_globals) if PY3: def iterkeys(d, **kw): return iter(d.keys(**kw)) def itervalues(d, **kw): return iter(d.values(**kw)) def iteritems(d, **kw): return iter(d.items(**kw)) def iterlists(d, **kw): return iter(d.lists(**kw)) viewkeys = operator.methodcaller("keys") viewvalues = operator.methodcaller("values") viewitems = operator.methodcaller("items") else: def iterkeys(d, **kw): return d.iterkeys(**kw) def itervalues(d, **kw): return d.itervalues(**kw) def iteritems(d, **kw): return d.iteritems(**kw) def iterlists(d, **kw): return d.iterlists(**kw) viewkeys = operator.methodcaller("viewkeys") viewvalues = operator.methodcaller("viewvalues") viewitems = operator.methodcaller("viewitems") _add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") _add_doc(itervalues, "Return an iterator over the values of a dictionary.") _add_doc(iteritems, "Return an iterator over the (key, value) pairs of a dictionary.") _add_doc(iterlists, "Return an iterator over the (key, [values]) pairs of a dictionary.") if PY3: def b(s): return s.encode("latin-1") def u(s): return s unichr = chr import struct int2byte = struct.Struct(">B").pack del struct byte2int = operator.itemgetter(0) indexbytes = operator.getitem iterbytes = iter import io StringIO = io.StringIO BytesIO = io.BytesIO _assertCountEqual = "assertCountEqual" if sys.version_info[1] <= 1: _assertRaisesRegex = "assertRaisesRegexp" _assertRegex = "assertRegexpMatches" else: _assertRaisesRegex = "assertRaisesRegex" _assertRegex = "assertRegex" else: def b(s): return s # Workaround for standalone backslash def u(s): return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") unichr = unichr int2byte = chr def byte2int(bs): return ord(bs[0]) def indexbytes(buf, i): return ord(buf[i]) iterbytes = functools.partial(itertools.imap, ord) import StringIO StringIO = BytesIO = StringIO.StringIO _assertCountEqual = "assertItemsEqual" _assertRaisesRegex = "assertRaisesRegexp" _assertRegex = "assertRegexpMatches" _add_doc(b, """Byte literal""") _add_doc(u, """Text literal""") def assertCountEqual(self, *args, **kwargs): return getattr(self, _assertCountEqual)(*args, **kwargs) def assertRaisesRegex(self, *args, **kwargs): return getattr(self, _assertRaisesRegex)(*args, **kwargs) def assertRegex(self, *args, **kwargs): return getattr(self, _assertRegex)(*args, **kwargs) if PY3: exec_ = getattr(moves.builtins, "exec") def reraise(tp, value, tb=None): try: if value is None: value = tp() if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value finally: value = None tb = None else: def exec_(_code_, _globs_=None, _locs_=None): """Execute code in a namespace.""" if _globs_ is None: frame = sys._getframe(1) _globs_ = frame.f_globals if _locs_ is None: _locs_ = frame.f_locals del frame elif _locs_ is None: _locs_ = _globs_ exec("""exec _code_ in _globs_, _locs_""") exec_("""def reraise(tp, value, tb=None): try: raise tp, value, tb finally: tb = None """) if sys.version_info[:2] == (3, 2): exec_("""def raise_from(value, from_value): try: if from_value is None: raise value raise value from from_value finally: value = None """) elif sys.version_info[:2] > (3, 2): exec_("""def raise_from(value, from_value): try: raise value from from_value finally: value = None """) else: def raise_from(value, from_value): raise value print_ = getattr(moves.builtins, "print", None) if print_ is None: def print_(*args, **kwargs): """The new-style print function for Python 2.4 and 2.5.""" fp = kwargs.pop("file", sys.stdout) if fp is None: return def write(data): if not isinstance(data, basestring): data = str(data) # If the file has an encoding, encode unicode with it. if (isinstance(fp, file) and isinstance(data, unicode) and fp.encoding is not None): errors = getattr(fp, "errors", None) if errors is None: errors = "strict" data = data.encode(fp.encoding, errors) fp.write(data) want_unicode = False sep = kwargs.pop("sep", None) if sep is not None: if isinstance(sep, unicode): want_unicode = True elif not isinstance(sep, str): raise TypeError("sep must be None or a string") end = kwargs.pop("end", None) if end is not None: if isinstance(end, unicode): want_unicode = True elif not isinstance(end, str): raise TypeError("end must be None or a string") if kwargs: raise TypeError("invalid keyword arguments to print()") if not want_unicode: for arg in args: if isinstance(arg, unicode): want_unicode = True break if want_unicode: newline = unicode("\n") space = unicode(" ") else: newline = "\n" space = " " if sep is None: sep = space if end is None: end = newline for i, arg in enumerate(args): if i: write(sep) write(arg) write(end) if sys.version_info[:2] < (3, 3): _print = print_ def print_(*args, **kwargs): fp = kwargs.get("file", sys.stdout) flush = kwargs.pop("flush", False) _print(*args, **kwargs) if flush and fp is not None: fp.flush() _add_doc(reraise, """Reraise an exception.""") if sys.version_info[0:2] < (3, 4): def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, updated=functools.WRAPPER_UPDATES): def wrapper(f): f = functools.wraps(wrapped, assigned, updated)(f) f.__wrapped__ = wrapped return f return wrapper else: wraps = functools.wraps def with_metaclass(meta, *bases): """Create a base class with a metaclass.""" # This requires a bit of explanation: the basic idea is to make a dummy # metaclass for one level of class instantiation that replaces itself with # the actual metaclass. class metaclass(type): def __new__(cls, name, this_bases, d): return meta(name, bases, d) @classmethod def __prepare__(cls, name, this_bases): return meta.__prepare__(name, bases) return type.__new__(metaclass, 'temporary_class', (), {}) def add_metaclass(metaclass): """Class decorator for creating a class with a metaclass.""" def wrapper(cls): orig_vars = cls.__dict__.copy() slots = orig_vars.get('__slots__') if slots is not None: if isinstance(slots, str): slots = [slots] for slots_var in slots: orig_vars.pop(slots_var) orig_vars.pop('__dict__', None) orig_vars.pop('__weakref__', None) return metaclass(cls.__name__, cls.__bases__, orig_vars) return wrapper def python_2_unicode_compatible(klass): """ A decorator that defines __unicode__ and __str__ methods under Python 2. Under Python 3 it does nothing. To support Python 2 and 3 with a single code base, define a __str__ method returning text and apply this decorator to the class. """ if PY2: if '__str__' not in klass.__dict__: raise ValueError("@python_2_unicode_compatible cannot be applied " "to %s because it doesn't define __str__()." % klass.__name__) klass.__unicode__ = klass.__str__ klass.__str__ = lambda self: self.__unicode__().encode('utf-8') return klass # Complete the moves implementation. # This code is at the end of this module to speed up module loading. # Turn this module into a package. __path__ = [] # required for PEP 302 and PEP 451 __package__ = __name__ # see PEP 366 @ReservedAssignment if globals().get("__spec__") is not None: __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable # Remove other six meta path importers, since they cause problems. This can # happen if six is removed from sys.modules and then reloaded. (Setuptools does # this for some reason.) if sys.meta_path: for i, importer in enumerate(sys.meta_path): # Here's some real nastiness: Another "instance" of the six module might # be floating around. Therefore, we can't use isinstance() to check for # the six meta path importer, since the other six instance will have # inserted an importer with different class. if (type(importer).__name__ == "_SixMetaPathImporter" and importer.name == __name__): del sys.meta_path[i] break del i, importer # Finally, add the importer to the meta path import hook. sys.meta_path.append(_importer) SABnzbd-2.3.2/tools/make_mo.py0000755000000000000000000002434513217005257014266 0ustar 00000000000000#!/usr/bin/python -OO # -*- coding: utf-8 -*- # Copyright 2010-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ make_mo - Compile PO files to MO files """ import glob import os import re import sys import gettext import subprocess PO_DIR = 'po/main' POE_DIR = 'po/email' PON_DIR = 'po/nsis' MO_DIR = 'locale' EMAIL_DIR = 'email' MO_LOCALE = '/LC_MESSAGES' DOMAIN = 'SABnzbd' DOMAIN_E = 'SABemail' DOMAIN_N = 'SABnsis' LANG_MARKER = 'language.txt' NSIS = 'NSIS_Installer.nsi' LanguageTable = { 'aa': ('Afar', 'Afaraf'), 'af': ('Afrikaans', 'Afrikaans'), 'ak': ('Akan', 'Akan'), 'sq': ('Albanian', 'Shqip'), 'an': ('Aragonese', 'Aragonés'), 'ae': ('Avestan', 'Avesta'), 'ay': ('Aymara', 'Aymararu'), 'bm': ('Bambara', 'Bamanankan'), 'eu': ('Basque', 'Euskara'), 'bi': ('Bislama', 'Bislama'), 'bs': ('Bosnian', 'Bosanskijezik'), 'br': ('Breton', 'Brezhoneg'), 'ca': ('Catalan', 'Català'), 'ch': ('Chamorro', 'Chamoru'), 'kw': ('Cornish', 'Kernewek'), 'co': ('Corsican', 'Corsu'), 'hr': ('Croatian', 'Hrvatski'), 'cs': ('Czech', 'Cesky, ceština'), 'da': ('Danish', 'Dansk'), 'nl': ('Dutch', 'Nederlands'), 'en': ('English', 'English'), 'eo': ('Esperanto', 'Esperanto'), 'et': ('Estonian', 'Eesti'), 'fo': ('Faroese', 'Føroyskt'), 'fj': ('Fijian', 'Vosa Vakaviti'), 'fi': ('Finnish', 'Suomi'), 'fr': ('French', 'Français'), 'gl': ('Galician', 'Galego'), 'de': ('German', 'Deutsch'), 'he': ('Hebrew', 'עִבְרִית‎'), 'hz': ('Herero', 'Otjiherero'), 'ho': ('Hiri Motu', 'Hiri Motu'), 'hu': ('Hungarian', 'Magyar'), 'id': ('Indonesian', 'Bahasa Indonesia'), 'ga': ('Irish', 'Gaeilge'), 'io': ('Ido', 'Ido'), 'is': ('Icelandic', 'Íslenska'), 'it': ('Italian', 'Italiano'), 'jv': ('Javanese', 'BasaJawa'), 'rw': ('Kinyarwanda', 'Ikinyarwanda'), 'kg': ('Kongo', 'KiKongo'), 'kj': ('Kwanyama', 'Kuanyama'), 'la': ('Latin', 'Lingua latina'), 'lb': ('Luxembourgish', 'Lëtzebuergesch'), 'lg': ('Luganda', 'Luganda'), 'li': ('Limburgish', 'Limburgs'), 'ln': ('Lingala', 'Lingála'), 'lt': ('Lithuanian', 'Lietuviukalba'), 'lv': ('Latvian', 'Latviešuvaloda'), 'gv': ('Manx', 'Gaelg'), 'mg': ('Malagasy', 'Malagasy fiteny'), 'mt': ('Maltese', 'Malti'), 'nb': ('Norwegian', 'Norsk'), # Bokmål 'nn': ('Norwegian', 'Norsk'), # Nynorsk 'no': ('Norwegian', 'Norsk'), 'oc': ('Occitan', 'Occitan'), 'om': ('Oromo', 'Afaan Oromoo'), 'pl': ('Polish', 'Polski'), 'pt': ('Portuguese', 'Português'), 'pt_BR': ('PortugueseBR', 'Português, Brasil'), # NSIS uses "PortugueseBR" 'rm': ('Romansh', 'Rumantsch grischun'), 'rn': ('Kirundi', 'kiRundi'), 'ro': ('Romanian', 'Româna'), 'sc': ('Sardinian', 'Sardu'), 'se': ('Northern Sami', 'Davvisámegiella'), 'sm': ('Samoan', 'Gagana fa\'a Samoa'), 'gd': ('Gaelic', 'Gàidhlig'), 'ru': ('Russian', 'русский язык'), 'sr': ('Serbian', 'српски'), 'sn': ('Shona', 'Chi Shona'), 'sk': ('Slovak', 'Slovencina'), 'sl': ('Slovene', 'Slovenšcina'), 'st': ('Southern Sotho', 'Sesotho'), 'es': ('Spanish', 'Español, castellano'), # NSIS cannot handle "Spanish Castilian" 'su': ('Sundanese', 'Basa Sunda'), 'sw': ('Swahili', 'Kiswahili'), 'ss': ('Swati', 'SiSwati'), 'sv': ('Swedish', 'Svenska'), 'tn': ('Tswana', 'Setswana'), 'to': ('Tonga (Tonga Islands)', 'faka Tonga'), 'tr': ('Turkish', 'Türkçe'), 'ts': ('Tsonga', 'Xitsonga'), 'tw': ('Twi', 'Twi'), 'ty': ('Tahitian', 'Reo Tahiti'), 'wa': ('Walloon', 'Walon'), 'cy': ('Welsh', 'Cymraeg'), 'wo': ('Wolof', 'Wollof'), 'fy': ('Western Frisian', 'Frysk'), 'xh': ('Xhosa', 'isi Xhosa'), 'yo': ('Yoruba', 'Yorùbá'), 'zu': ('Zulu', 'isi Zulu'), 'zh_CN': ('SimpChinese', '简体中文'), } # Filter for retrieving readable language from PO file RE_LANG = re.compile(r'"Language-Description:\s([^"]+)\\n') def run(cmd): """ Run system command, returns exit-code and stdout """ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) txt = p.stdout.read() return p.wait(), txt def process_po_folder(domain, folder, extra=''): """ Process each PO file in folder """ result = True for fname in glob.glob(os.path.join(folder, '*.po')): basename = os.path.split(fname)[1] name = os.path.splitext(basename)[0] mo_path = os.path.normpath('%s/%s%s' % (MO_DIR, name, MO_LOCALE)) mo_name = '%s.mo' % domain if not os.path.exists(mo_path): os.makedirs(mo_path) # Create the MO file mo_file = os.path.join(mo_path, mo_name) print 'Compile %s' % mo_file ret, output = run('%s %s -o "%s" "%s"' % (TOOL, extra, mo_file, fname)) if ret != 0: print '\nMissing %s. Please install this package first.' % TOOL exit(1) if 'WARNING:' in output: print output result = False return result def remove_mo_files(): """ Remove MO files in locale """ for root, dirs, files in os.walk(MO_DIR, topdown=False): for f in files: if not f.startswith(DOMAIN): os.remove(os.path.join(root, f)) def translate_tmpl(prefix, lng): """ Translate template 'prefix' into language 'lng' """ src = open(EMAIL_DIR + '/%s-en.tmpl' % prefix, 'r') data = src.read().decode('utf-8') src.close() data = _(data).encode('utf-8') fp = open('email/%s-%s.tmpl' % (prefix, lng), 'wb') if not -1 < data.find('UTF-8') < 30: fp.write('#encoding UTF-8\n') fp.write(data) fp.close() def make_templates(): """ Create email templates """ if not os.path.exists('email'): os.makedirs('email') for path in glob.glob(os.path.join(MO_DIR, '*')): lng = os.path.split(path)[1] if lng != 'en' and os.path.exists(os.path.join(POE_DIR,lng+'.po')): print 'Create email template for %s' % lng trans = gettext.translation(DOMAIN_E, MO_DIR, [lng], fallback=False, codeset='latin-1') # The unicode flag will make _() return Unicode trans.install(unicode=True, names=['lgettext']) translate_tmpl('email', lng) translate_tmpl('rss', lng) translate_tmpl('badfetch', lng) mo_path = os.path.normpath('%s/%s%s/%s.mo' % (MO_DIR, path, MO_LOCALE, DOMAIN_E)) if os.path.exists(mo_path): os.remove(mo_path) def patch_nsis(): """ Patch translation into the NSIS script """ RE_NSIS = re.compile(r'^(\s*LangString\s+\w+\s+\$\{LANG_)(\w+)\}\s+(".*)', re.I) RE_NSIS = re.compile(r'^(\s*LangString\s+)(\w+)(\s+\$\{LANG_)(\w+)\}\s+(".*)', re.I) languages = [os.path.split(path)[1] for path in glob.glob(os.path.join(MO_DIR, '*'))] src = open(NSIS, 'r') new = [] for line in src: m = RE_NSIS.search(line) if m: leader = m.group(1) item = m.group(2) rest = m.group(3) langname = m.group(4).upper() text = m.group(5).strip('"\n') if langname == 'ENGLISH': # Write back old content new.append(line) # Replace silly $\ construction with just a \ text = text.replace('$\\"', '"').replace('$\\', '\\') for lcode in languages: lng = LanguageTable.get(lcode) if lng and lcode != 'en': lng = lng[0].decode('utf-8').encode('latin-1').upper() if item == 'MsgLangCode': trans = lcode else: trans = gettext.translation(DOMAIN_N, MO_DIR, [lcode], fallback=False, codeset='latin-1') # The unicode flag will make _() return Unicode trans.install(unicode=True, names=['lgettext']) trans = _(text).encode('utf-8') trans = trans.replace('\r', '').replace('\n', '\\r\\n') trans = trans.replace('\\', '$\\').replace('"', '$\\"') line = '%s%s%s%s} "%s"\n' % (leader, item, rest, lng, trans) new.append(line) elif lng is None: print 'Warning: unsupported language %s (%s), add to table in this script' % (langname, lcode) else: new.append(line) src.close() dst = open(NSIS + '.tmp', 'w') for line in new: dst.write(line) dst.close() #---------------------------------------------------------------------------- # Determine location of MsgFmt tool path, py = os.path.split(sys.argv[0]) tl = os.path.abspath(os.path.normpath(os.path.join(path, 'msgfmt.py'))) if os.path.exists(tl): if os.name == 'nt': TOOL = 'python "%s"' % tl else: TOOL = '"%s"' % tl result = True if len(sys.argv) > 1 and sys.argv[1] == 'all': print 'NSIS MO file' result = result and process_po_folder(DOMAIN_N, PON_DIR) print "Patch NSIS script" patch_nsis() print 'Email MO files' result = result and process_po_folder(DOMAIN_E, POE_DIR) print "Create email templates from MO files" make_templates() print 'Main program MO files' # -n option added to remove all newlines from the translations result = result and process_po_folder(DOMAIN, PO_DIR, '-n') print "Remove temporary templates" remove_mo_files() print if result: exit(0) else: print 'WARNINGS present!' exit(1) SABnzbd-2.3.2/tools/msgfmt.py0000755000000000000000000001377113217005257014154 0ustar 00000000000000#! /usr/bin/env python # -*- coding: iso-8859-1 -*- # Written by Martin v. L�wis r"""Generate binary message catalog from textual translation description. This program converts a textual Uniforum-style message catalog (.po file) into a binary GNU catalog (.mo file). This is essentially the same function as the GNU msgfmt program, however, it is a simpler implementation. Usage: msgfmt.py [OPTIONS] filename.po Options: -o file --output-file=file Specify the output file to write to. If omitted, output will go to a file named filename.mo (based off the input file name). -n Remove all newlines (\r\n) from translations -h --help Print this message and exit. -V --version Display version information and exit. """ import sys import os import getopt import struct import array import re __version__ = "1.1" MESSAGES = {} nonewlines = False # Detector for HTML elements RE_HTML = re.compile('<[^>]+>') def usage(code, msg=''): print >> sys.stderr, __doc__ if msg: print >> sys.stderr, msg sys.exit(code) def add(id, str, fuzzy): """ Add a non-fuzzy translation to the dictionary. """ global MESSAGES, nonewlines, RE_HTML if not fuzzy and str: if id.count('%s') == str.count('%s'): if nonewlines and id and ('\r' in str or '\n' in str) and RE_HTML.search(str): MESSAGES[id] = str.replace('\n', '').replace('\r', '') else: MESSAGES[id] = str else: print 'WARNING: %s mismatch, skipping!' print ' %s' % id print ' %s' % str def generate(): """ Return the generated output. """ global MESSAGES keys = MESSAGES.keys() # the keys are sorted in the .mo file keys.sort() offsets = [] ids = strs = '' for id in keys: # For each string, we need size and file offset. Each string is NUL # terminated; the NUL does not count into the size. offsets.append((len(ids), len(id), len(strs), len(MESSAGES[id]))) ids += id + '\0' strs += MESSAGES[id] + '\0' output = '' # The header is 7 32-bit unsigned integers. We don't use hash tables, so # the keys start right after the index tables. # translated string. keystart = 7 * 4 + 16 * len(keys) # and the values start after the keys valuestart = keystart + len(ids) koffsets = [] voffsets = [] # The string table first has the list of keys, then the list of values. # Each entry has first the size of the string, then the file offset. for o1, l1, o2, l2 in offsets: koffsets += [l1, o1 + keystart] voffsets += [l2, o2 + valuestart] offsets = koffsets + voffsets output = struct.pack("Iiiiiii", 0x950412deL, # Magic 0, # Version len(keys), # # of entries 7 * 4, # start of key index 7 * 4 + len(keys) * 8, # start of value index 0, 0) # size and offset of hash table output += array.array("i", offsets).tostring() output += ids output += strs return output def make(filename, outfile): ID = 1 STR = 2 # Compute .mo name from .po name and arguments if filename.endswith('.po'): infile = filename else: infile = filename + '.po' if outfile is None: outfile = os.path.splitext(infile)[0] + '.mo' try: lines = open(infile).readlines() except IOError, msg: print >> sys.stderr, msg sys.exit(1) section = None fuzzy = 0 # Parse the catalog lno = 0 for l in lines: lno += 1 # If we get a comment line after a msgstr, this is a new entry if l[0] == '#' and section == STR: add(msgid, msgstr, fuzzy) section = None fuzzy = 0 # Record a fuzzy mark if l[:2] == '#,' and 'fuzzy' in l: fuzzy = 1 # Skip comments if l[0] == '#': continue # Now we are in a msgid section, output previous section if l.startswith('msgid'): if section == STR: add(msgid, msgstr, fuzzy) section = ID l = l[5:] msgid = msgstr = '' # Now we are in a msgstr section elif l.startswith('msgstr'): section = STR l = l[6:] # Skip empty lines l = l.strip() if not l: continue # XXX: Does this always follow Python escape semantics? l = eval(l) if section == ID: msgid += l elif section == STR: msgstr += l else: print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \ 'before:' print >> sys.stderr, l sys.exit(1) # Add last entry if section == STR: add(msgid, msgstr, fuzzy) # Compute output output = generate() try: open(outfile, "wb").write(output) except IOError, msg: print >> sys.stderr, msg def main(): global nonewlines try: opts, args = getopt.getopt(sys.argv[1:], 'nhVo:', ['help', 'version', 'output-file=']) except getopt.error, msg: usage(1, msg) outfile = None # parse options for opt, arg in opts: if opt in ('-h', '--help'): usage(0) elif opt in ('-V', '--version'): print >> sys.stderr, "msgfmt.py", __version__ sys.exit(0) elif opt in ('-o', '--output-file'): outfile = arg elif opt in ('-n', ): nonewlines = True # do it if not args: print >> sys.stderr, 'No input file given' print >> sys.stderr, "Try `msgfmt --help' for more information." return for filename in args: make(filename, outfile) if __name__ == '__main__': main() SABnzbd-2.3.2/util/apireg.py0000644000000000000000000000751313217005257013735 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2012-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ util.apireg - Registration of API connection info """ import _winreg def reg_info(user): """ Return the reg key for API """ if user: # Normally use the USER part of the registry section = _winreg.HKEY_CURRENT_USER keypath = r"Software\SABnzbd" else: # A Windows Service will use the service key instead section = _winreg.HKEY_LOCAL_MACHINE keypath = r"SYSTEM\CurrentControlSet\Services\SABnzbd" return section, keypath def get_connection_info(user=True): """ Return URL of the API running SABnzbd instance 'user' == True will first try user's registry, otherwise system is used """ section, keypath = reg_info(user) url = None try: hive = _winreg.ConnectRegistry(None, section) key = _winreg.OpenKey(hive, keypath + r'\api') for i in range(0, _winreg.QueryInfoKey(key)[1]): name, value, val_type = _winreg.EnumValue(key, i) if name == 'url': url = value _winreg.CloseKey(key) except WindowsError: pass finally: _winreg.CloseKey(hive) # Nothing in user's registry, try system registry if user and not url: url = get_connection_info(user=False) return url def set_connection_info(url, user=True): """ Set API info in register """ section, keypath = reg_info(user) try: hive = _winreg.ConnectRegistry(None, section) try: key = _winreg.CreateKey(hive, keypath) except: pass key = _winreg.OpenKey(hive, keypath) mykey = _winreg.CreateKey(key, 'api') _winreg.SetValueEx(mykey, 'url', None, _winreg.REG_SZ, url) _winreg.CloseKey(mykey) _winreg.CloseKey(key) except WindowsError: if user: set_connection_info(url, user=False) pass finally: _winreg.CloseKey(hive) def del_connection_info(user=True): """ Remove API info from register """ section, keypath = reg_info(user) try: hive = _winreg.ConnectRegistry(None, section) key = _winreg.OpenKey(hive, keypath) _winreg.DeleteKey(key, 'api') _winreg.CloseKey(key) except WindowsError: if user: del_connection_info(user=False) pass finally: _winreg.CloseKey(hive) def get_install_lng(): """ Return language-code used by the installer """ lng = 0 try: hive = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) key = _winreg.OpenKey(hive, r"Software\SABnzbd") for i in range(0, _winreg.QueryInfoKey(key)[1]): name, value, val_type = _winreg.EnumValue(key, i) if name == 'Installer Language': lng = value _winreg.CloseKey(key) except WindowsError: pass finally: _winreg.CloseKey(hive) return lng if __name__ == '__main__': print 'URL = %s' % get_connection_info() print 'Language = %s' % get_install_lng() # del_connection_info() # set_connection_info('localhost', '8080', 'blabla', user=False) SABnzbd-2.3.2/util/mailslot.py0000644000000000000000000001000513217005257014300 0ustar 00000000000000#!/usr/bin/python -OO # Copyright 2008-2017 The SABnzbd-Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ sabnzbd.mailslot - Mailslot communication """ import os from win32file import GENERIC_WRITE, FILE_SHARE_READ, \ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL from ctypes import c_uint, c_buffer, byref, sizeof, windll # Win32API Shortcuts CreateFile = windll.kernel32.CreateFileA ReadFile = windll.kernel32.ReadFile WriteFile = windll.kernel32.WriteFile CloseHandle = windll.kernel32.CloseHandle CreateMailslot = windll.kernel32.CreateMailslotA class MailSlot(object): """ Simple Windows Mailslot communication """ slotname = r'mailslot\SABnzbd\ServiceSlot' def __init__(self): self.handle = -1 def create(self, timeout): """ Create the Mailslot, after this only receiving is possible timeout is the read timeout used for receive calls. """ slot = r'\\.\%s' % MailSlot.slotname self.handle = CreateMailslot(slot, 0, timeout, None) return self.handle != -1 def connect(self): """ Connect to existing Mailslot so that writing is possible """ slot = r'\\%s\%s' % (os.environ['COMPUTERNAME'], MailSlot.slotname) self.handle = CreateFile(slot, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) return self.handle != -1 def disconnect(self): """ Disconnect from Mailslot """ if self.handle != -1: CloseHandle(self.handle) self.handle = -1 return True def send(self, command): """ Send one message to Mailslot """ if self.handle == -1: return False w = c_uint() return bool(WriteFile(self.handle, command, len(command), byref(w), 0)) def receive(self): """ Receive one message from Mailslot """ r = c_uint() buf = c_buffer(1024) if ReadFile(self.handle, buf, sizeof(buf), byref(r), 0): return buf.value else: return None ############################################################################## # Simple test # # First start "mailslot.py server" in one process, # Then start "mailslot.py client" in another. # Five "restart" and one "stop" will be send from client to server. # The server will stop after receiving "stop" ############################################################################## if __name__ == '__main__': import sys from time import sleep if not __debug__: print 'Run this test in non-optimized mode' exit(1) if len(sys.argv) > 1 and 'server' in sys.argv[1]: recv = MailSlot() ret = recv.create(2) assert ret, 'Failed to create' while True: data = recv.receive() if data is not None: print data if data.startswith('stop'): break sleep(2.0) recv.disconnect() elif len(sys.argv) > 1 and 'client' in sys.argv[1]: send = MailSlot() ret = send.connect() assert ret, 'Failed to connect' for n in xrange(5): ret = send.send('restart') assert ret, 'Failed to send' sleep(2.0) send.send('stop') assert ret, 'Failed to send' send.disconnect() else: print 'Usage: mailslot.py server|client' SABnzbd-2.3.2/util/__init__.py0000644000000000000000000000000013217005257014205 0ustar 00000000000000SABnzbd-2.3.2/0000755000000000000000000000000013224674737011516 5ustar rootrootSABnzbd-2.3.2/interfaces/0000755000000000000000000000000013224674747013642 5ustar rootrootSABnzbd-2.3.2/interfaces/Plush/0000755000000000000000000000000013224674737014734 5ustar rootrootSABnzbd-2.3.2/interfaces/Plush/templates/0000755000000000000000000000000013224674737016732 5ustar rootrootSABnzbd-2.3.2/interfaces/Plush/templates/static/0000755000000000000000000000000013224674737020221 5ustar rootrootSABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/0000755000000000000000000000000013224674737022552 5ustar rootrootSABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/0000755000000000000000000000000013224674740023333 5ustar rootrootSABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.colorbox_1.3.17.2.js0000644000000000000000000006532312701006716030005 0ustar rootroot// ColorBox v1.3.17.2 - a full featured, light-weight, customizable lightbox based on jQuery 1.3+ // Copyright (c) 2011 Jack Moore - jack@colorpowered.com // Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php (function ($, document, window) { var // ColorBox Default Settings. // See http://colorpowered.com/colorbox for details. defaults = { transition: "elastic", speed: 300, width: false, initialWidth: "600", innerWidth: false, maxWidth: false, height: false, initialHeight: "450", innerHeight: false, maxHeight: false, scalePhotos: true, scrolling: true, inline: false, html: false, iframe: false, fastIframe: true, photo: false, href: false, title: false, rel: false, opacity: 0.9, preloading: true, current: "image {current} of {total}", previous: "previous", next: "next", close: "close", open: false, returnFocus: true, loop: true, slideshow: false, slideshowAuto: true, slideshowSpeed: 2500, slideshowStart: "start slideshow", slideshowStop: "stop slideshow", onOpen: false, onLoad: false, onComplete: false, onCleanup: false, onClosed: false, overlayClose: true, escKey: true, arrowKey: true, top: false, bottom: false, left: false, right: false, fixed: false, data: false }, // Abstracting the HTML and event identifiers for easy rebranding colorbox = 'colorbox', prefix = 'cbox', boxElement = prefix + 'Element', // Events event_open = prefix + '_open', event_load = prefix + '_load', event_complete = prefix + '_complete', event_cleanup = prefix + '_cleanup', event_closed = prefix + '_closed', event_purge = prefix + '_purge', // Special Handling for IE isIE = $.browser.msie && !$.support.opacity, // Detects IE6,7,8. IE9 supports opacity. Feature detection alone gave a false positive on at least one phone browser and on some development versions of Chrome, hence the user-agent test. isIE6 = isIE && $.browser.version < 7, event_ie6 = prefix + '_IE6', // Cached jQuery Object Variables $overlay, $box, $wrap, $content, $topBorder, $leftBorder, $rightBorder, $bottomBorder, $related, $window, $loaded, $loadingBay, $loadingOverlay, $title, $current, $slideshow, $next, $prev, $close, $groupControls, // Variables for cached values or use across multiple functions settings, interfaceHeight, interfaceWidth, loadedHeight, loadedWidth, element, index, photo, open, active, closing, handler, loadingTimer, publicMethod; // **************** // HELPER FUNCTIONS // **************** // jQuery object generator to reduce code size function $div(id, cssText, div) { div = document.createElement('div'); if (id) { div.id = prefix + id; } div.style.cssText = cssText || ''; return $(div); } // Convert '%' and 'px' values to integers function setSize(size, dimension) { return Math.round((/%/.test(size) ? ((dimension === 'x' ? $window.width() : $window.height()) / 100) : 1) * parseInt(size, 10)); } // Checks an href to see if it is a photo. // There is a force photo option (photo: true) for hrefs that cannot be matched by this regex. function isImage(url) { return settings.photo || /\.(gif|png|jpg|jpeg|bmp)(?:\?([^#]*))?(?:#(\.*))?$/i.test(url); } // Assigns function results to their respective settings. This allows functions to be used as values. function makeSettings(i) { settings = $.extend({}, $.data(element, colorbox)); for (i in settings) { if ($.isFunction(settings[i]) && i.substring(0, 2) !== 'on') { // checks to make sure the function isn't one of the callbacks, they will be handled at the appropriate time. settings[i] = settings[i].call(element); } } settings.rel = settings.rel || element.rel || 'nofollow'; settings.href = settings.href || $(element).attr('href'); settings.title = settings.title || element.title; if (typeof settings.href === "string") { settings.href = $.trim(settings.href); } } function trigger(event, callback) { if (callback) { callback.call(element); } $.event.trigger(event); } // Slideshow functionality function slideshow() { var timeOut, className = prefix + "Slideshow_", click = "click." + prefix, start, stop, clear; if (settings.slideshow && $related[1]) { start = function () { $slideshow .text(settings.slideshowStop) .unbind(click) .bind(event_complete, function () { if (index < $related.length - 1 || settings.loop) { timeOut = setTimeout(publicMethod.next, settings.slideshowSpeed); } }) .bind(event_load, function () { clearTimeout(timeOut); }) .one(click + ' ' + event_cleanup, stop); $box.removeClass(className + "off").addClass(className + "on"); timeOut = setTimeout(publicMethod.next, settings.slideshowSpeed); }; stop = function () { clearTimeout(timeOut); $slideshow .text(settings.slideshowStart) .unbind([event_complete, event_load, event_cleanup, click].join(' ')) .one(click, start); $box.removeClass(className + "on").addClass(className + "off"); }; if (settings.slideshowAuto) { start(); } else { stop(); } } else { $box.removeClass(className + "off " + className + "on"); } } function launch(target) { if (!closing) { element = target; makeSettings(); $related = $(element); index = 0; if (settings.rel !== 'nofollow') { $related = $('.' + boxElement).filter(function () { var relRelated = $.data(this, colorbox).rel || this.rel; return (relRelated === settings.rel); }); index = $related.index(element); // Check direct calls to ColorBox. if (index === -1) { $related = $related.add(element); index = $related.length - 1; } } if (!open) { open = active = true; // Prevents the page-change action from queuing up if the visitor holds down the left or right keys. $box.show(); if (settings.returnFocus) { try { element.blur(); $(element).one(event_closed, function () { try { this.focus(); } catch (e) { // do nothing } }); } catch (e) { // do nothing } } // +settings.opacity avoids a problem in IE when using non-zero-prefixed-string-values, like '.5' $overlay.css({"opacity": +settings.opacity, "cursor": settings.overlayClose ? "pointer" : "auto"}).show(); // Opens inital empty ColorBox prior to content being loaded. settings.w = setSize(settings.initialWidth, 'x'); settings.h = setSize(settings.initialHeight, 'y'); publicMethod.position(); if (isIE6) { $window.bind('resize.' + event_ie6 + ' scroll.' + event_ie6, function () { $overlay.css({width: $window.width(), height: $window.height(), top: $window.scrollTop(), left: $window.scrollLeft()}); }).trigger('resize.' + event_ie6); } trigger(event_open, settings.onOpen); $groupControls.add($title).hide(); $close.html(settings.close).show(); } publicMethod.load(true); } } // **************** // PUBLIC FUNCTIONS // Usage format: $.fn.colorbox.close(); // Usage from within an iframe: parent.$.fn.colorbox.close(); // **************** publicMethod = $.fn[colorbox] = $[colorbox] = function (options, callback) { var $this = this; options = options || {}; if (!$this[0]) { if ($this.selector) { // if a selector was given and it didn't match any elements, go ahead and exit. return $this; } // if no selector was given (ie. $.colorbox()), create a temporary element to work with $this = $(''); options.open = true; // assume an immediate open } if (callback) { options.onComplete = callback; } $this.each(function () { $.data(this, colorbox, $.extend({}, $.data(this, colorbox) || defaults, options)); $(this).addClass(boxElement); }); if (($.isFunction(options.open) && options.open.call($this)) || options.open) { launch($this[0]); } return $this; }; // Initialize ColorBox: store common calculations, preload the interface graphics, append the html. // This preps ColorBox for a speedy open when clicked, and minimizes the burdon on the browser by only // having to run once, instead of each time colorbox is opened. publicMethod.init = function () { // Create & Append jQuery Objects $window = $(window); $box = $div().attr({id: colorbox, 'class': isIE ? prefix + (isIE6 ? 'IE6' : 'IE') : ''}); $overlay = $div("Overlay", isIE6 ? 'position:absolute' : '').hide(); $wrap = $div("Wrapper"); $content = $div("Content").append( $loaded = $div("LoadedContent", 'width:0; height:0; overflow:hidden'), $loadingOverlay = $div("LoadingOverlay").add($div("LoadingGraphic")), $title = $div("Title"), $current = $div("Current"), $next = $div("Next"), $prev = $div("Previous"), $slideshow = $div("Slideshow").bind(event_open, slideshow), $close = $div("Close") ); $wrap.append( // The 3x3 Grid that makes up ColorBox $div().append( $div("TopLeft"), $topBorder = $div("TopCenter"), $div("TopRight") ), $div(false, 'clear:left').append( $leftBorder = $div("MiddleLeft"), $content, $rightBorder = $div("MiddleRight") ), $div(false, 'clear:left').append( $div("BottomLeft"), $bottomBorder = $div("BottomCenter"), $div("BottomRight") ) ).children().children().css({'float': 'left'}); $loadingBay = $div(false, 'position:absolute; width:9999px; visibility:hidden; display:none'); $('body').prepend($overlay, $box.append($wrap, $loadingBay)); $content.children() .hover(function () { $(this).addClass('hover'); }, function () { $(this).removeClass('hover'); }).addClass('hover'); // Cache values needed for size calculations interfaceHeight = $topBorder.height() + $bottomBorder.height() + $content.outerHeight(true) - $content.height();//Subtraction needed for IE6 interfaceWidth = $leftBorder.width() + $rightBorder.width() + $content.outerWidth(true) - $content.width(); loadedHeight = $loaded.outerHeight(true); loadedWidth = $loaded.outerWidth(true); // Setting padding to remove the need to do size conversions during the animation step. $box.css({"padding-bottom": interfaceHeight, "padding-right": interfaceWidth}).hide(); // Setup button events. // Anonymous functions here keep the public method from being cached, thereby allowing them to be redefined on the fly. $next.click(function () { publicMethod.next(); }); $prev.click(function () { publicMethod.prev(); }); $close.click(function () { publicMethod.close(); }); $groupControls = $next.add($prev).add($current).add($slideshow); // Adding the 'hover' class allowed the browser to load the hover-state // background graphics in case the images were not part of a sprite. The class can now can be removed. $content.children().removeClass('hover'); $overlay.click(function () { if (settings.overlayClose) { publicMethod.close(); } }); // Set Navigation Key Bindings $(document).bind('keydown.' + prefix, function (e) { var key = e.keyCode; if (open && settings.escKey && key === 27) { e.preventDefault(); publicMethod.close(); } if (open && settings.arrowKey && $related[1]) { if (key === 37) { e.preventDefault(); $prev.click(); } else if (key === 39) { e.preventDefault(); $next.click(); } } }); }; publicMethod.remove = function () { $box.add($overlay).remove(); $('.' + boxElement).removeData(colorbox).removeClass(boxElement); }; publicMethod.position = function (speed, loadedCallback) { var top = 0, left = 0; $window.unbind('resize.' + prefix); // remove the modal so that it doesn't influence the document width/height $box.hide(); if (settings.fixed && !isIE6) { $box.css({position: 'fixed'}); } else { top = $window.scrollTop(); left = $window.scrollLeft(); $box.css({position: 'absolute'}); } // keeps the top and left positions within the browser's viewport. if (settings.right !== false) { left += Math.max($window.width() - settings.w - loadedWidth - interfaceWidth - setSize(settings.right, 'x'), 0); } else if (settings.left !== false) { left += setSize(settings.left, 'x'); } else { left += Math.round(Math.max($window.width() - settings.w - loadedWidth - interfaceWidth, 0) / 2); } if (settings.bottom !== false) { top += Math.max(document.documentElement.clientHeight - settings.h - loadedHeight - interfaceHeight - setSize(settings.bottom, 'y'), 0); } else if (settings.top !== false) { top += setSize(settings.top, 'y'); } else { top += Math.round(Math.max(document.documentElement.clientHeight - settings.h - loadedHeight - interfaceHeight, 0) / 2); } $box.show(); // setting the speed to 0 to reduce the delay between same-sized content. speed = ($box.width() === settings.w + loadedWidth && $box.height() === settings.h + loadedHeight) ? 0 : speed || 0; // this gives the wrapper plenty of breathing room so it's floated contents can move around smoothly, // but it has to be shrank down around the size of div#colorbox when it's done. If not, // it can invoke an obscure IE bug when using iframes. $wrap[0].style.width = $wrap[0].style.height = "9999px"; function modalDimensions(that) { // loading overlay height has to be explicitly set for IE6. $topBorder[0].style.width = $bottomBorder[0].style.width = $content[0].style.width = that.style.width; $loadingOverlay[0].style.height = $loadingOverlay[1].style.height = $content[0].style.height = $leftBorder[0].style.height = $rightBorder[0].style.height = that.style.height; } $box.dequeue().animate({width: settings.w + loadedWidth, height: settings.h + loadedHeight, top: top, left: left}, { duration: speed, complete: function () { modalDimensions(this); active = false; // shrink the wrapper down to exactly the size of colorbox to avoid a bug in IE's iframe implementation. $wrap[0].style.width = (settings.w + loadedWidth + interfaceWidth) + "px"; $wrap[0].style.height = (settings.h + loadedHeight + interfaceHeight) + "px"; if (loadedCallback) { loadedCallback(); } setTimeout(function(){ // small delay before binding onresize due to an IE8 bug. $window.bind('resize.' + prefix, publicMethod.position); }, 1); }, step: function () { modalDimensions(this); } }); }; publicMethod.resize = function (options) { if (open) { options = options || {}; if (options.width) { settings.w = setSize(options.width, 'x') - loadedWidth - interfaceWidth; } if (options.innerWidth) { settings.w = setSize(options.innerWidth, 'x'); } $loaded.css({width: settings.w}); if (options.height) { settings.h = setSize(options.height, 'y') - loadedHeight - interfaceHeight; } if (options.innerHeight) { settings.h = setSize(options.innerHeight, 'y'); } if (!options.innerHeight && !options.height) { var $child = $loaded.wrapInner("
").children(); // temporary wrapper to get an accurate estimate of just how high the total content should be. settings.h = $child.height(); $child.replaceWith($child.children()); // ditch the temporary wrapper div used in height calculation } $loaded.css({height: settings.h}); publicMethod.position(settings.transition === "none" ? 0 : settings.speed); } }; publicMethod.prep = function (object) { if (!open) { return; } var callback, speed = settings.transition === "none" ? 0 : settings.speed; $loaded.remove(); $loaded = $div('LoadedContent').append(object); function getWidth() { settings.w = settings.w || $loaded.width(); settings.w = settings.mw && settings.mw < settings.w ? settings.mw : settings.w; return settings.w; } function getHeight() { settings.h = settings.h || $loaded.height(); settings.h = settings.mh && settings.mh < settings.h ? settings.mh : settings.h; return settings.h; } $loaded.hide() .appendTo($loadingBay.show())// content has to be appended to the DOM for accurate size calculations. .css({width: getWidth(), overflow: settings.scrolling ? 'auto' : 'hidden'}) .css({height: getHeight()})// sets the height independently from the width in case the new width influences the value of height. .prependTo($content); $loadingBay.hide(); // floating the IMG removes the bottom line-height and fixed a problem where IE miscalculates the width of the parent element as 100% of the document width. //$(photo).css({'float': 'none', marginLeft: 'auto', marginRight: 'auto'}); $(photo).css({'float': 'none'}); // Hides SELECT elements in IE6 because they would otherwise sit on top of the overlay. if (isIE6) { $('select').not($box.find('select')).filter(function () { return this.style.visibility !== 'hidden'; }).css({'visibility': 'hidden'}).one(event_cleanup, function () { this.style.visibility = 'inherit'; }); } callback = function () { var prev, prevSrc, next, nextSrc, total = $related.length, iframe, complete; if (!open) { return; } function removeFilter() { if (isIE) { $box[0].style.removeAttribute('filter'); } } complete = function () { clearTimeout(loadingTimer); $loadingOverlay.hide(); trigger(event_complete, settings.onComplete); }; if (isIE) { //This fadeIn helps the bicubic resampling to kick-in. if (photo) { $loaded.fadeIn(100); } } $title.html(settings.title).add($loaded).show(); if (total > 1) { // handle grouping if (typeof settings.current === "string") { $current.html(settings.current.replace('{current}', index + 1).replace('{total}', total)).show(); } $next[(settings.loop || index < total - 1) ? "show" : "hide"]().html(settings.next); $prev[(settings.loop || index) ? "show" : "hide"]().html(settings.previous); prev = index ? $related[index - 1] : $related[total - 1]; next = index < total - 1 ? $related[index + 1] : $related[0]; if (settings.slideshow) { $slideshow.show(); } // Preloads images within a rel group if (settings.preloading) { nextSrc = $.data(next, colorbox).href || next.href; prevSrc = $.data(prev, colorbox).href || prev.href; nextSrc = $.isFunction(nextSrc) ? nextSrc.call(next) : nextSrc; prevSrc = $.isFunction(prevSrc) ? prevSrc.call(prev) : prevSrc; if (isImage(nextSrc)) { $('')[0].src = nextSrc; } if (isImage(prevSrc)) { $('')[0].src = prevSrc; } } } else { $groupControls.hide(); } if (settings.iframe) { iframe = $(''; document.body.appendChild(d); var i = document.getElementById(n); if (c && typeof(c.onComplete) == 'function') { i.onComplete = c.onComplete; } return n; }, form : function(f, name) { f.setAttribute('target', name); }, submit : function(f, c) { AIM.form(f, AIM.frame(c)); if (c && typeof(c.onStart) == 'function') { return c.onStart(); } else { return true; } }, loaded : function(id) { var i = document.getElementById(id); if (i.contentDocument) { var d = i.contentDocument; } else if (i.contentWindow) { var d = i.contentWindow.document; } else { var d = window.frames[id].document; } if (d.location.href == "about:blank") { return; } if (typeof(i.onComplete) == 'function') { i.onComplete(d.body.innerHTML); } } }SABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.ui.dialog.js0000644000000000000000000005242112701006716027055 0ustar rootroot/* * jQuery UI Dialog 1.8.15 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Dialog * * Depends: * jquery.ui.core.js * jquery.ui.widget.js * jquery.ui.button.js * jquery.ui.draggable.js * jquery.ui.mouse.js * jquery.ui.position.js * jquery.ui.resizable.js */ (function( $, undefined ) { var uiDialogClasses = 'ui-dialog ' + 'ui-widget ' + 'ui-widget-content ' + 'ui-corner-all ', sizeRelatedOptions = { buttons: true, height: true, maxHeight: true, maxWidth: true, minHeight: true, minWidth: true, width: true }, resizableRelatedOptions = { maxHeight: true, maxWidth: true, minHeight: true, minWidth: true }, // support for jQuery 1.3.2 - handle common attrFn methods for dialog attrFn = $.attrFn || { val: true, css: true, html: true, text: true, data: true, width: true, height: true, offset: true, click: true }; $.widget("ui.dialog", { options: { autoOpen: true, buttons: {}, closeOnEscape: true, closeText: 'close', dialogClass: '', draggable: true, hide: null, height: 'auto', maxHeight: false, maxWidth: false, minHeight: 150, minWidth: 150, modal: false, position: { my: 'center', at: 'center', collision: 'fit', // ensure that the titlebar is never outside the document using: function(pos) { var topOffset = $(this).css(pos).offset().top; if (topOffset < 0) { $(this).css('top', pos.top - topOffset); } } }, resizable: true, show: null, stack: true, title: '', width: 300, zIndex: 1000 }, _create: function() { this.originalTitle = this.element.attr('title'); // #5742 - .attr() might return a DOMElement if ( typeof this.originalTitle !== "string" ) { this.originalTitle = ""; } this.options.title = this.options.title || this.originalTitle; var self = this, options = self.options, title = options.title || ' ', titleId = $.ui.dialog.getTitleId(self.element), uiDialog = (self.uiDialog = $('
')) .appendTo(document.body) .hide() .addClass(uiDialogClasses + options.dialogClass) .css({ zIndex: options.zIndex }) // setting tabIndex makes the div focusable // setting outline to 0 prevents a border on focus in Mozilla .attr('tabIndex', -1).css('outline', 0).keydown(function(event) { if (options.closeOnEscape && event.keyCode && event.keyCode === $.ui.keyCode.ESCAPE) { self.close(event); event.preventDefault(); } }) .attr({ role: 'dialog', 'aria-labelledby': titleId }) .mousedown(function(event) { self.moveToTop(false, event); }), uiDialogContent = self.element .show() .removeAttr('title') .addClass( 'ui-dialog-content ' + 'ui-widget-content') .appendTo(uiDialog), uiDialogTitlebar = (self.uiDialogTitlebar = $('
')) .addClass( 'ui-dialog-titlebar ' + 'ui-widget-header ' + 'ui-corner-all ' + 'ui-helper-clearfix' ) .prependTo(uiDialog), uiDialogTitlebarClose = $('
') .addClass( 'ui-dialog-titlebar-close ' + 'ui-corner-all' ) .attr('role', 'button') .hover( function() { uiDialogTitlebarClose.addClass('ui-state-hover'); }, function() { uiDialogTitlebarClose.removeClass('ui-state-hover'); } ) .focus(function() { uiDialogTitlebarClose.addClass('ui-state-focus'); }) .blur(function() { uiDialogTitlebarClose.removeClass('ui-state-focus'); }) .click(function(event) { self.close(event); return false; }) .appendTo(uiDialogTitlebar), uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('')) .addClass( 'ui-icon ' + 'ui-icon-closethick' ) .text(options.closeText) .appendTo(uiDialogTitlebarClose), uiDialogTitle = $('') .addClass('ui-dialog-title') .attr('id', titleId) .html(title) .prependTo(uiDialogTitlebar); //handling of deprecated beforeclose (vs beforeClose) option //Ticket #4669 http://dev.jqueryui.com/ticket/4669 //TODO: remove in 1.9pre if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) { options.beforeClose = options.beforeclose; } uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection(); if (options.draggable && $.fn.draggable) { self._makeDraggable(); } if (options.resizable && $.fn.resizable) { self._makeResizable(); } self._createButtons(options.buttons); self._isOpen = false; if ($.fn.bgiframe) { uiDialog.bgiframe(); } }, _init: function() { if ( this.options.autoOpen ) { this.open(); } }, destroy: function() { var self = this; if (self.overlay) { self.overlay.destroy(); } self.uiDialog.hide(); self.element .unbind('.dialog') .removeData('dialog') .removeClass('ui-dialog-content ui-widget-content') .hide().appendTo('body'); self.uiDialog.remove(); if (self.originalTitle) { self.element.attr('title', self.originalTitle); } return self; }, widget: function() { return this.uiDialog; }, close: function(event) { var self = this, maxZ, thisZ; if (false === self._trigger('beforeClose', event)) { return; } if (self.overlay) { self.overlay.destroy(); } self.uiDialog.unbind('keypress.ui-dialog'); self._isOpen = false; if (self.options.hide) { self.uiDialog.hide(self.options.hide, function() { self._trigger('close', event); }); } else { self.uiDialog.hide(); self._trigger('close', event); } $.ui.dialog.overlay.resize(); // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) if (self.options.modal) { maxZ = 0; $('.ui-dialog').each(function() { if (this !== self.uiDialog[0]) { thisZ = $(this).css('z-index'); if(!isNaN(thisZ)) { maxZ = Math.max(maxZ, thisZ); } } }); $.ui.dialog.maxZ = maxZ; } return self; }, isOpen: function() { return this._isOpen; }, // the force parameter allows us to move modal dialogs to their correct // position on open moveToTop: function(force, event) { var self = this, options = self.options, saveScroll; if ((options.modal && !force) || (!options.stack && !options.modal)) { return self._trigger('focus', event); } if (options.zIndex > $.ui.dialog.maxZ) { $.ui.dialog.maxZ = options.zIndex; } if (self.overlay) { $.ui.dialog.maxZ += 1; self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ); } //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed. // http://ui.jquery.com/bugs/ticket/3193 saveScroll = { scrollTop: self.element.scrollTop(), scrollLeft: self.element.scrollLeft() }; $.ui.dialog.maxZ += 1; self.uiDialog.css('z-index', $.ui.dialog.maxZ); self.element.attr(saveScroll); self._trigger('focus', event); return self; }, open: function() { if (this._isOpen) { return; } var self = this, options = self.options, uiDialog = self.uiDialog; self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null; self._size(); self._position(options.position); uiDialog.show(options.show); self.moveToTop(true); // prevent tabbing out of modal dialogs if (options.modal) { uiDialog.bind('keypress.ui-dialog', function(event) { if (event.keyCode !== $.ui.keyCode.TAB) { return; } var tabbables = $(':tabbable', this), first = tabbables.filter(':first'), last = tabbables.filter(':last'); if (event.target === last[0] && !event.shiftKey) { first.focus(1); return false; } else if (event.target === first[0] && event.shiftKey) { last.focus(1); return false; } }); } // set focus to the first tabbable element in the content area or the first button // if there are no tabbable elements, set focus on the dialog itself $(self.element.find(':tabbable').get().concat( uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat( uiDialog.get()))).eq(0).focus(); self._isOpen = true; self._trigger('open'); return self; }, _createButtons: function(buttons) { var self = this, hasButtons = false, uiDialogButtonPane = $('
') .addClass( 'ui-dialog-buttonpane ' + 'ui-widget-content ' + 'ui-helper-clearfix' ), uiButtonSet = $( "
" ) .addClass( "ui-dialog-buttonset" ) .appendTo( uiDialogButtonPane ); // if we already have a button pane, remove it self.uiDialog.find('.ui-dialog-buttonpane').remove(); if (typeof buttons === 'object' && buttons !== null) { $.each(buttons, function() { return !(hasButtons = true); }); } if (hasButtons) { $.each(buttons, function(name, props) { props = $.isFunction( props ) ? { click: props, text: name } : props; var button = $('') .click(function() { props.click.apply(self.element[0], arguments); }) .appendTo(uiButtonSet); // can't use .attr( props, true ) with jQuery 1.3.2. $.each( props, function( key, value ) { if ( key === "click" ) { return; } if ( key in attrFn ) { button[ key ]( value ); } else { button.attr( key, value ); } }); if ($.fn.button) { button.button(); } }); uiDialogButtonPane.appendTo(self.uiDialog); } }, _makeDraggable: function() { var self = this, options = self.options, doc = $(document), heightBeforeDrag; function filteredUi(ui) { return { position: ui.position, offset: ui.offset }; } self.uiDialog.draggable({ cancel: '.ui-dialog-content, .ui-dialog-titlebar-close', handle: '.ui-dialog-titlebar', containment: 'document', start: function(event, ui) { heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height(); $(this).height($(this).height()).addClass("ui-dialog-dragging"); self._trigger('dragStart', event, filteredUi(ui)); }, drag: function(event, ui) { self._trigger('drag', event, filteredUi(ui)); }, stop: function(event, ui) { options.position = [ui.position.left - doc.scrollLeft(), ui.position.top - doc.scrollTop()]; $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag); self._trigger('dragStop', event, filteredUi(ui)); $.ui.dialog.overlay.resize(); } }); }, _makeResizable: function(handles) { handles = (handles === undefined ? this.options.resizable : handles); var self = this, options = self.options, // .ui-resizable has position: relative defined in the stylesheet // but dialogs have to use absolute or fixed positioning position = self.uiDialog.css('position'), resizeHandles = (typeof handles === 'string' ? handles : 'n,e,s,w,se,sw,ne,nw' ); function filteredUi(ui) { return { originalPosition: ui.originalPosition, originalSize: ui.originalSize, position: ui.position, size: ui.size }; } self.uiDialog.resizable({ cancel: '.ui-dialog-content', containment: 'document', alsoResize: self.element, maxWidth: options.maxWidth, maxHeight: options.maxHeight, minWidth: options.minWidth, minHeight: self._minHeight(), handles: resizeHandles, start: function(event, ui) { $(this).addClass("ui-dialog-resizing"); self._trigger('resizeStart', event, filteredUi(ui)); }, resize: function(event, ui) { self._trigger('resize', event, filteredUi(ui)); }, stop: function(event, ui) { $(this).removeClass("ui-dialog-resizing"); options.height = $(this).height(); options.width = $(this).width(); self._trigger('resizeStop', event, filteredUi(ui)); $.ui.dialog.overlay.resize(); } }) .css('position', position) .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se'); }, _minHeight: function() { var options = this.options; if (options.height === 'auto') { return options.minHeight; } else { return Math.min(options.minHeight, options.height); } }, _position: function(position) { var myAt = [], offset = [0, 0], isVisible; if (position) { // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( // if (typeof position == 'string' || $.isArray(position)) { // myAt = $.isArray(position) ? position : position.split(' '); if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) { myAt = position.split ? position.split(' ') : [position[0], position[1]]; if (myAt.length === 1) { myAt[1] = myAt[0]; } $.each(['left', 'top'], function(i, offsetPosition) { if (+myAt[i] === myAt[i]) { offset[i] = myAt[i]; myAt[i] = offsetPosition; } }); position = { my: myAt.join(" "), at: myAt.join(" "), offset: offset.join(" ") }; } position = $.extend({}, $.ui.dialog.prototype.options.position, position); } else { position = $.ui.dialog.prototype.options.position; } // need to show the dialog to get the actual offset in the position plugin isVisible = this.uiDialog.is(':visible'); if (!isVisible) { this.uiDialog.show(); } this.uiDialog // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 .css({ top: 0, left: 0 }) .position($.extend({ of: window }, position)); if (!isVisible) { this.uiDialog.hide(); } }, _setOptions: function( options ) { var self = this, resizableOptions = {}, resize = false; $.each( options, function( key, value ) { self._setOption( key, value ); if ( key in sizeRelatedOptions ) { resize = true; } if ( key in resizableRelatedOptions ) { resizableOptions[ key ] = value; } }); if ( resize ) { this._size(); } if ( this.uiDialog.is( ":data(resizable)" ) ) { this.uiDialog.resizable( "option", resizableOptions ); } }, _setOption: function(key, value){ var self = this, uiDialog = self.uiDialog; switch (key) { //handling of deprecated beforeclose (vs beforeClose) option //Ticket #4669 http://dev.jqueryui.com/ticket/4669 //TODO: remove in 1.9pre case "beforeclose": key = "beforeClose"; break; case "buttons": self._createButtons(value); break; case "closeText": // ensure that we always pass a string self.uiDialogTitlebarCloseText.text("" + value); break; case "dialogClass": uiDialog .removeClass(self.options.dialogClass) .addClass(uiDialogClasses + value); break; case "disabled": if (value) { uiDialog.addClass('ui-dialog-disabled'); } else { uiDialog.removeClass('ui-dialog-disabled'); } break; case "draggable": var isDraggable = uiDialog.is( ":data(draggable)" ); if ( isDraggable && !value ) { uiDialog.draggable( "destroy" ); } if ( !isDraggable && value ) { self._makeDraggable(); } break; case "position": self._position(value); break; case "resizable": // currently resizable, becoming non-resizable var isResizable = uiDialog.is( ":data(resizable)" ); if (isResizable && !value) { uiDialog.resizable('destroy'); } // currently resizable, changing handles if (isResizable && typeof value === 'string') { uiDialog.resizable('option', 'handles', value); } // currently non-resizable, becoming resizable if (!isResizable && value !== false) { self._makeResizable(value); } break; case "title": // convert whatever was passed in o a string, for html() to not throw up $(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || ' ')); break; } $.Widget.prototype._setOption.apply(self, arguments); }, _size: function() { /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content * divs will both have width and height set, so we need to reset them */ var options = this.options, nonContentHeight, minContentHeight, isVisible = this.uiDialog.is( ":visible" ); // reset content sizing this.element.show().css({ width: 'auto', minHeight: 0, height: 0 }); if (options.minWidth > options.width) { options.width = options.minWidth; } // reset wrapper sizing // determine the height of all the non-content elements nonContentHeight = this.uiDialog.css({ height: 'auto', width: options.width }) .height(); minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); if ( options.height === "auto" ) { // only needed for IE6 support if ( $.support.minHeight ) { this.element.css({ minHeight: minContentHeight, height: "auto" }); } else { this.uiDialog.show(); var autoHeight = this.element.css( "height", "auto" ).height(); if ( !isVisible ) { this.uiDialog.hide(); } this.element.height( Math.max( autoHeight, minContentHeight ) ); } } else { this.element.height( Math.max( options.height - nonContentHeight, 0 ) ); } if (this.uiDialog.is(':data(resizable)')) { this.uiDialog.resizable('option', 'minHeight', this._minHeight()); } } }); $.extend($.ui.dialog, { version: "1.8.15", uuid: 0, maxZ: 0, getTitleId: function($el) { var id = $el.attr('id'); if (!id) { this.uuid += 1; id = this.uuid; } return 'ui-dialog-title-' + id; }, overlay: function(dialog) { this.$el = $.ui.dialog.overlay.create(dialog); } }); $.extend($.ui.dialog.overlay, { instances: [], // reuse old instances due to IE memory leak with alpha transparency (see #5185) oldInstances: [], maxZ: 0, events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), function(event) { return event + '.dialog-overlay'; }).join(' '), create: function(dialog) { if (this.instances.length === 0) { // prevent use of anchors and inputs // we use a setTimeout in case the overlay is created from an // event that we're going to be cancelling (see #2804) setTimeout(function() { // handle $(el).dialog().dialog('close') (see #4065) if ($.ui.dialog.overlay.instances.length) { $(document).bind($.ui.dialog.overlay.events, function(event) { // stop events if the z-index of the target is < the z-index of the overlay // we cannot return true when we don't want to cancel the event (#3523) if ($(event.target).zIndex() < $.ui.dialog.overlay.maxZ) { return false; } }); } }, 1); // allow closing by pressing the escape key $(document).bind('keydown.dialog-overlay', function(event) { if (dialog.options.closeOnEscape && event.keyCode && event.keyCode === $.ui.keyCode.ESCAPE) { dialog.close(event); event.preventDefault(); } }); // handle window resize $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); } var $el = (this.oldInstances.pop() || $('
').addClass('ui-widget-overlay')) .appendTo(document.body) .css({ width: this.width(), height: this.height() }); if ($.fn.bgiframe) { $el.bgiframe(); } this.instances.push($el); return $el; }, destroy: function($el) { var indexOf = $.inArray($el, this.instances); if (indexOf != -1){ this.oldInstances.push(this.instances.splice(indexOf, 1)[0]); } if (this.instances.length === 0) { $([document, window]).unbind('.dialog-overlay'); } $el.remove(); // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) var maxZ = 0; $.each(this.instances, function() { maxZ = Math.max(maxZ, this.css('z-index')); }); this.maxZ = maxZ; }, height: function() { var scrollHeight, offsetHeight; // handle IE 6 if ($.browser.msie && $.browser.version < 7) { scrollHeight = Math.max( document.documentElement.scrollHeight, document.body.scrollHeight ); offsetHeight = Math.max( document.documentElement.offsetHeight, document.body.offsetHeight ); if (scrollHeight < offsetHeight) { return $(window).height() + 'px'; } else { return scrollHeight + 'px'; } // handle "good" browsers } else { return $(document).height() + 'px'; } }, width: function() { var scrollWidth, offsetWidth; // handle IE if ( $.browser.msie ) { scrollWidth = Math.max( document.documentElement.scrollWidth, document.body.scrollWidth ); offsetWidth = Math.max( document.documentElement.offsetWidth, document.body.offsetWidth ); if (scrollWidth < offsetWidth) { return $(window).width() + 'px'; } else { return scrollWidth + 'px'; } // handle "good" browsers } else { return $(document).width() + 'px'; } }, resize: function() { /* If the dialog is draggable and the user drags it past the * right edge of the window, the document becomes wider so we * need to stretch the overlay. If the user then drags the * dialog back to the left, the document will become narrower, * so we need to shrink the overlay to the appropriate size. * This is handled by shrinking the overlay before setting it * to the full document size. */ var $overlays = $([]); $.each($.ui.dialog.overlay.instances, function() { $overlays = $overlays.add(this); }); $overlays.css({ width: 0, height: 0 }).css({ width: $.ui.dialog.overlay.width(), height: $.ui.dialog.overlay.height() }); } }); $.extend($.ui.dialog.overlay.prototype, { destroy: function() { $.ui.dialog.overlay.destroy(this.$el); } }); }(jQuery)); SABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.tablednd.0.5.js0000644000000000000000000004041112701006716027254 0ustar rootroot/** * TableDnD plug-in for JQuery, allows you to drag and drop table rows * You can set up various options to control how the system will work * Copyright (c) Denis Howlett * Licensed like jQuery, see http://docs.jquery.com/License. * * Configuration options: * * onDragStyle * This is the style that is assigned to the row during drag. There are limitations to the styles that can be * associated with a row (such as you can't assign a border--well you can, but it won't be * displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as * a map (as used in the jQuery css(...) function). * onDropStyle * This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations * to what you can do. Also this replaces the original style, so again consider using onDragClass which * is simply added and then removed on drop. * onDragClass * This class is added for the duration of the drag and then removed when the row is dropped. It is more * flexible than using onDragStyle since it can be inherited by the row cells and other content. The default * is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your * stylesheet. * onDrop * Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table * and the row that was dropped. You can work out the new order of the rows by using * table.rows. * onDragStart * Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the * table and the row which the user has started to drag. * onAllowDrop * Pass a function that will be called as a row is over another row. If the function returns true, allow * dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under * the cursor. It returns a boolean: true allows the drop, false doesn't allow it. * scrollAmount * This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the * window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2, * FF3 beta * dragHandle * This is the name of a class that you assign to one or more cells in each row that is draggable. If you * specify this class, then you are responsible for setting cursor: move in the CSS and only these cells * will have the drag behaviour. If you do not specify a dragHandle, then you get the old behaviour where * the whole row is draggable. * * Other ways to control behaviour: * * Add class="nodrop" to any rows for which you don't want to allow dropping, and class="nodrag" to any rows * that you don't want to be draggable. * * Inside the onDrop method you can also call $.tableDnD.serialize() this returns a string of the form * []=&[]= so that you can send this back to the server. The table must have * an ID as must all the rows. * * Other methods: * * $("...").tableDnDUpdate() * Will update all the matching tables, that is it will reapply the mousedown method to the rows (or handle cells). * This is useful if you have updated the table rows using Ajax and you want to make the table draggable again. * The table maintains the original configuration (so you don't have to specify it again). * * $("...").tableDnDSerialize() * Will serialize and return the serialized string as above, but for each of the matching tables--so it can be * called from anywhere and isn't dependent on the currentTable being set up correctly before calling * * Known problems: * - Auto-scoll has some problems with IE7 (it scrolls even when it shouldn't), work-around: set scrollAmount to 0 * * Version 0.2: 2008-02-20 First public version * Version 0.3: 2008-02-07 Added onDragStart option * Made the scroll amount configurable (default is 5 as before) * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes * Added onAllowDrop to control dropping * Fixed a bug which meant that you couldn't set the scroll amount in both directions * Added serialize method * Version 0.5: 2008-05-16 Changed so that if you specify a dragHandle class it doesn't make the whole row * draggable * Improved the serialize method to use a default (and settable) regular expression. * Added tableDnDupate() and tableDnDSerialize() to be called when you are outside the table */ jQuery.tableDnD = { /** Keep hold of the current table being dragged */ currentTable : null, /** Keep hold of the current drag object if any */ dragObject: null, /** The current mouse offset */ mouseOffset: null, /** Remember the old value of Y so that we don't do too much processing */ oldY: 0, /** Actually build the structure */ build: function(options) { // Set up the defaults if any this.each(function() { // This is bound to each matching table, set up the defaults and override with user options this.tableDnDConfig = $.extend({ onDragStyle: null, onDropStyle: null, // Add in the default class for whileDragging onDragClass: "tDnD_whileDrag", onDrop: null, onDragStart: null, scrollAmount: 5, serializeRegexp: /[^\-]*$/, // The regular expression to use to trim row IDs serializeParamName: null, // If you want to specify another parameter name instead of the table ID dragHandle: null // If you give the name of a class here, then only Cells with this class will be draggable }, options || {}); // Now make the rows draggable jQuery.tableDnD.makeDraggable(this); }); // Now we need to capture the mouse up and mouse move event // We can use bind so that we don't interfere with other event handlers jQuery(document) .bind('mousemove', jQuery.tableDnD.mousemove) .bind('mouseup', jQuery.tableDnD.mouseup); // Don't break the chain return this; }, /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */ makeDraggable: function(table) { var config = table.tableDnDConfig; if (table.tableDnDConfig.dragHandle) { // We only need to add the event to the specified cells var cells = $("td."+table.tableDnDConfig.dragHandle, table); cells.each(function() { // The cell is bound to "this" jQuery(this).mousedown(function(ev) { jQuery.tableDnD.dragObject = this.parentNode; jQuery.tableDnD.currentTable = table; jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev); if (config.onDragStart) { // Call the onDrop method if there is one config.onDragStart(table, this); } return false; }); }) } else { // For backwards compatibility, we add the event to the whole row var rows = jQuery("tr", table); // get all the rows as a wrapped set rows.each(function() { // Iterate through each row, the row is bound to "this" var row = $(this); if (! row.hasClass("nodrag")) { row.mousedown(function(ev) { if (ev.target.tagName == "TD") { jQuery.tableDnD.dragObject = this; jQuery.tableDnD.currentTable = table; jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev); if (config.onDragStart) { // Call the onDrop method if there is one config.onDragStart(table, this); } return false; } }).css("cursor", "move"); // Store the tableDnD object } }); } }, updateTables: function() { this.each(function() { // this is now bound to each matching table if (this.tableDnDConfig) { jQuery.tableDnD.makeDraggable(this); } }) }, /** Get the mouse coordinates from the event (allowing for browser differences) */ mouseCoords: function(ev){ if(ev.pageX || ev.pageY){ return {x:ev.pageX, y:ev.pageY}; } return { x:ev.clientX + document.body.scrollLeft - document.body.clientLeft, y:ev.clientY + document.body.scrollTop - document.body.clientTop }; }, /** Given a target element and a mouse event, get the mouse offset from that element. To do this we need the element's position and the mouse position */ getMouseOffset: function(target, ev) { ev = ev || window.event; var docPos = this.getPosition(target); var mousePos = this.mouseCoords(ev); return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y}; }, /** Get the position of an element by going up the DOM tree and adding up all the offsets */ getPosition: function(e){ var left = 0; var top = 0; /** Safari fix -- thanks to Luis Chato for this! */ if (e.offsetHeight == 0) { /** Safari 2 doesn't correctly grab the offsetTop of a table row this is detailed here: http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/ the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild. note that firefox will return a text node as a first child, so designing a more thorough solution may need to take that into account, for now this seems to work in firefox, safari, ie */ e = e.firstChild; // a table cell } while (e.offsetParent){ left += e.offsetLeft; top += e.offsetTop; e = e.offsetParent; } left += e.offsetLeft; top += e.offsetTop; return {x:left, y:top}; }, mousemove: function(ev) { if (jQuery.tableDnD.dragObject == null) { return; } var dragObj = jQuery(jQuery.tableDnD.dragObject); var config = jQuery.tableDnD.currentTable.tableDnDConfig; var mousePos = jQuery.tableDnD.mouseCoords(ev); var y = mousePos.y - jQuery.tableDnD.mouseOffset.y; //auto scroll the window var yOffset = window.pageYOffset; if (document.all) { // Windows version //yOffset=document.body.scrollTop; if (typeof document.compatMode != 'undefined' && document.compatMode != 'BackCompat') { yOffset = document.documentElement.scrollTop; } else if (typeof document.body != 'undefined') { yOffset=document.body.scrollTop; } } if (mousePos.y-yOffset < config.scrollAmount) { window.scrollBy(0, -config.scrollAmount); } else { var windowHeight = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight; if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) { window.scrollBy(0, config.scrollAmount); } } if (y != jQuery.tableDnD.oldY) { // work out if we're going up or down... var movingDown = y > jQuery.tableDnD.oldY; // update the old value jQuery.tableDnD.oldY = y; // update the style to show we're dragging if (config.onDragClass) { dragObj.addClass(config.onDragClass); } else { dragObj.css(config.onDragStyle); } // If we're over a row then move the dragged row to there so that the user sees the // effect dynamically var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y); if (currentRow) { // TODO worry about what happens when there are multiple TBODIES if (movingDown && jQuery.tableDnD.dragObject != currentRow) { jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling); } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) { jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow); } } } return false; }, /** We're only worried about the y position really, because we can only move rows up and down */ findDropTargetRow: function(draggedRow, y) { var rows = jQuery.tableDnD.currentTable.rows; for (var i=0; i rowY - rowHeight) && (y < (rowY + rowHeight))) { // that's the row we're over // If it's the same as the current row, ignore it if (row == draggedRow) {return null;} var config = jQuery.tableDnD.currentTable.tableDnDConfig; if (config.onAllowDrop) { if (config.onAllowDrop(draggedRow, row)) { return row; } else { return null; } } else { // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic) var nodrop = $(row).hasClass("nodrop"); if (! nodrop) { return row; } else { return null; } } return row; } } return null; }, mouseup: function(e) { if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) { var droppedRow = jQuery.tableDnD.dragObject; var config = jQuery.tableDnD.currentTable.tableDnDConfig; // If we have a dragObject, then we need to release it, // The row will already have been moved to the right place so we just reset stuff if (config.onDragClass) { jQuery(droppedRow).removeClass(config.onDragClass); } else { jQuery(droppedRow).css(config.onDropStyle); } jQuery.tableDnD.dragObject = null; if (config.onDrop) { // Call the onDrop method if there is one config.onDrop(jQuery.tableDnD.currentTable, droppedRow); } jQuery.tableDnD.currentTable = null; // let go of the table too } }, serialize: function() { if (jQuery.tableDnD.currentTable) { return jQuery.tableDnD.serializeTable(jQuery.tableDnD.currentTable); } else { return "Error: No Table id set, you need to set an id on your table and every row"; } }, serializeTable: function(table) { var result = ""; var tableId = table.id; var rows = table.rows; for (var i=0; i 0) result += "&"; var rowId = rows[i].id; if (rowId && rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) { rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0]; } result += tableId + '[]=' + rows[i].id; } return result; }, serializeTables: function() { var result = ""; this.each(function() { // this is now bound to each matching table result += jQuery.tableDnD.serializeTable(this); }); return result; } } jQuery.fn.extend( { tableDnD : jQuery.tableDnD.build, tableDnDUpdate : jQuery.tableDnD.updateTables, tableDnDSerialize: jQuery.tableDnD.serializeTables } );SABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.ui.selectable.js0000644000000000000000000001527412701006716027726 0ustar rootroot/* * jQuery UI Selectable 1.8.15 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Selectables * * Depends: * jquery.ui.core.js * jquery.ui.mouse.js * jquery.ui.widget.js */ (function( $, undefined ) { $.widget("ui.selectable", $.ui.mouse, { options: { appendTo: 'body', autoRefresh: true, distance: 0, filter: '*', tolerance: 'touch' }, _create: function() { var self = this; this.element.addClass("ui-selectable"); this.dragged = false; // cache selectee children based on filter var selectees; this.refresh = function() { selectees = $(self.options.filter, self.element[0]); selectees.each(function() { var $this = $(this); var pos = $this.offset(); $.data(this, "selectable-item", { element: this, $element: $this, left: pos.left, top: pos.top, right: pos.left + $this.outerWidth(), bottom: pos.top + $this.outerHeight(), startselected: false, selected: $this.hasClass('ui-selected'), selecting: $this.hasClass('ui-selecting'), unselecting: $this.hasClass('ui-unselecting') }); }); }; this.refresh(); this.selectees = selectees.addClass("ui-selectee"); this._mouseInit(); this.helper = $("
"); }, destroy: function() { this.selectees .removeClass("ui-selectee") .removeData("selectable-item"); this.element .removeClass("ui-selectable ui-selectable-disabled") .removeData("selectable") .unbind(".selectable"); this._mouseDestroy(); return this; }, _mouseStart: function(event) { var self = this; this.opos = [event.pageX, event.pageY]; if (this.options.disabled) return; var options = this.options; this.selectees = $(options.filter, this.element[0]); this._trigger("start", event); $(options.appendTo).append(this.helper); // position helper (lasso) this.helper.css({ "left": event.clientX, "top": event.clientY, "width": 0, "height": 0 }); if (options.autoRefresh) { this.refresh(); } this.selectees.filter('.ui-selected').each(function() { var selectee = $.data(this, "selectable-item"); selectee.startselected = true; if (!event.metaKey) { selectee.$element.removeClass('ui-selected'); selectee.selected = false; selectee.$element.addClass('ui-unselecting'); selectee.unselecting = true; // selectable UNSELECTING callback self._trigger("unselecting", event, { unselecting: selectee.element }); } }); $(event.target).parents().andSelf().each(function() { var selectee = $.data(this, "selectable-item"); if (selectee) { var doSelect = !event.metaKey || !selectee.$element.hasClass('ui-selected'); selectee.$element .removeClass(doSelect ? "ui-unselecting" : "ui-selected") .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); selectee.unselecting = !doSelect; selectee.selecting = doSelect; selectee.selected = doSelect; // selectable (UN)SELECTING callback if (doSelect) { self._trigger("selecting", event, { selecting: selectee.element }); } else { self._trigger("unselecting", event, { unselecting: selectee.element }); } return false; } }); }, _mouseDrag: function(event) { var self = this; this.dragged = true; if (this.options.disabled) return; var options = this.options; var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); this.selectees.each(function() { var selectee = $.data(this, "selectable-item"); //prevent helper from being selected if appendTo: selectable if (!selectee || selectee.element == self.element[0]) return; var hit = false; if (options.tolerance == 'touch') { hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); } else if (options.tolerance == 'fit') { hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); } if (hit) { // SELECT if (selectee.selected) { selectee.$element.removeClass('ui-selected'); selectee.selected = false; } if (selectee.unselecting) { selectee.$element.removeClass('ui-unselecting'); selectee.unselecting = false; } if (!selectee.selecting) { selectee.$element.addClass('ui-selecting'); selectee.selecting = true; // selectable SELECTING callback self._trigger("selecting", event, { selecting: selectee.element }); } } else { // UNSELECT if (selectee.selecting) { if (event.metaKey && selectee.startselected) { selectee.$element.removeClass('ui-selecting'); selectee.selecting = false; selectee.$element.addClass('ui-selected'); selectee.selected = true; } else { selectee.$element.removeClass('ui-selecting'); selectee.selecting = false; if (selectee.startselected) { selectee.$element.addClass('ui-unselecting'); selectee.unselecting = true; } // selectable UNSELECTING callback self._trigger("unselecting", event, { unselecting: selectee.element }); } } if (selectee.selected) { if (!event.metaKey && !selectee.startselected) { selectee.$element.removeClass('ui-selected'); selectee.selected = false; selectee.$element.addClass('ui-unselecting'); selectee.unselecting = true; // selectable UNSELECTING callback self._trigger("unselecting", event, { unselecting: selectee.element }); } } } }); return false; }, _mouseStop: function(event) { var self = this; this.dragged = false; var options = this.options; $('.ui-unselecting', this.element[0]).each(function() { var selectee = $.data(this, "selectable-item"); selectee.$element.removeClass('ui-unselecting'); selectee.unselecting = false; selectee.startselected = false; self._trigger("unselected", event, { unselected: selectee.element }); }); $('.ui-selecting', this.element[0]).each(function() { var selectee = $.data(this, "selectable-item"); selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); selectee.selecting = false; selectee.selected = true; selectee.startselected = true; self._trigger("selected", event, { selected: selectee.element }); }); this._trigger("stop", event); this.helper.remove(); return false; } }); $.extend($.ui.selectable, { version: "1.8.15" }); })(jQuery); SABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.ui.position.js0000644000000000000000000001626312701006716027466 0ustar rootroot/* * jQuery UI Position 1.8.15 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Position */ (function( $, undefined ) { $.ui = $.ui || {}; var horizontalPositions = /left|center|right/, verticalPositions = /top|center|bottom/, center = "center", _position = $.fn.position, _offset = $.fn.offset; $.fn.position = function( options ) { if ( !options || !options.of ) { return _position.apply( this, arguments ); } // make a copy, we don't want to modify arguments options = $.extend( {}, options ); var target = $( options.of ), targetElem = target[0], collision = ( options.collision || "flip" ).split( " " ), offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ], targetWidth, targetHeight, basePosition; if ( targetElem.nodeType === 9 ) { targetWidth = target.width(); targetHeight = target.height(); basePosition = { top: 0, left: 0 }; // TODO: use $.isWindow() in 1.9 } else if ( targetElem.setTimeout ) { targetWidth = target.width(); targetHeight = target.height(); basePosition = { top: target.scrollTop(), left: target.scrollLeft() }; } else if ( targetElem.preventDefault ) { // force left top to allow flipping options.at = "left top"; targetWidth = targetHeight = 0; basePosition = { top: options.of.pageY, left: options.of.pageX }; } else { targetWidth = target.outerWidth(); targetHeight = target.outerHeight(); basePosition = target.offset(); } // force my and at to have valid horizontal and veritcal positions // if a value is missing or invalid, it will be converted to center $.each( [ "my", "at" ], function() { var pos = ( options[this] || "" ).split( " " ); if ( pos.length === 1) { pos = horizontalPositions.test( pos[0] ) ? pos.concat( [center] ) : verticalPositions.test( pos[0] ) ? [ center ].concat( pos ) : [ center, center ]; } pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center; pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center; options[ this ] = pos; }); // normalize collision option if ( collision.length === 1 ) { collision[ 1 ] = collision[ 0 ]; } // normalize offset option offset[ 0 ] = parseInt( offset[0], 10 ) || 0; if ( offset.length === 1 ) { offset[ 1 ] = offset[ 0 ]; } offset[ 1 ] = parseInt( offset[1], 10 ) || 0; if ( options.at[0] === "right" ) { basePosition.left += targetWidth; } else if ( options.at[0] === center ) { basePosition.left += targetWidth / 2; } if ( options.at[1] === "bottom" ) { basePosition.top += targetHeight; } else if ( options.at[1] === center ) { basePosition.top += targetHeight / 2; } basePosition.left += offset[ 0 ]; basePosition.top += offset[ 1 ]; return this.each(function() { var elem = $( this ), elemWidth = elem.outerWidth(), elemHeight = elem.outerHeight(), marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0, marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0, collisionWidth = elemWidth + marginLeft + ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ), collisionHeight = elemHeight + marginTop + ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ), position = $.extend( {}, basePosition ), collisionPosition; if ( options.my[0] === "right" ) { position.left -= elemWidth; } else if ( options.my[0] === center ) { position.left -= elemWidth / 2; } if ( options.my[1] === "bottom" ) { position.top -= elemHeight; } else if ( options.my[1] === center ) { position.top -= elemHeight / 2; } // prevent fractions (see #5280) position.left = Math.round( position.left ); position.top = Math.round( position.top ); collisionPosition = { left: position.left - marginLeft, top: position.top - marginTop }; $.each( [ "left", "top" ], function( i, dir ) { if ( $.ui.position[ collision[i] ] ) { $.ui.position[ collision[i] ][ dir ]( position, { targetWidth: targetWidth, targetHeight: targetHeight, elemWidth: elemWidth, elemHeight: elemHeight, collisionPosition: collisionPosition, collisionWidth: collisionWidth, collisionHeight: collisionHeight, offset: offset, my: options.my, at: options.at }); } }); if ( $.fn.bgiframe ) { elem.bgiframe(); } elem.offset( $.extend( position, { using: options.using } ) ); }); }; $.ui.position = { fit: { left: function( position, data ) { var win = $( window ), over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(); position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left ); }, top: function( position, data ) { var win = $( window ), over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(); position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top ); } }, flip: { left: function( position, data ) { if ( data.at[0] === center ) { return; } var win = $( window ), over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(), myOffset = data.my[ 0 ] === "left" ? -data.elemWidth : data.my[ 0 ] === "right" ? data.elemWidth : 0, atOffset = data.at[ 0 ] === "left" ? data.targetWidth : -data.targetWidth, offset = -2 * data.offset[ 0 ]; position.left += data.collisionPosition.left < 0 ? myOffset + atOffset + offset : over > 0 ? myOffset + atOffset + offset : 0; }, top: function( position, data ) { if ( data.at[1] === center ) { return; } var win = $( window ), over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(), myOffset = data.my[ 1 ] === "top" ? -data.elemHeight : data.my[ 1 ] === "bottom" ? data.elemHeight : 0, atOffset = data.at[ 1 ] === "top" ? data.targetHeight : -data.targetHeight, offset = -2 * data.offset[ 1 ]; position.top += data.collisionPosition.top < 0 ? myOffset + atOffset + offset : over > 0 ? myOffset + atOffset + offset : 0; } } }; // offset setter from jQuery 1.4 if ( !$.offset.setOffset ) { $.offset.setOffset = function( elem, options ) { // set position first, in-case top/left are set even on static elem if ( /static/.test( $.curCSS( elem, "position" ) ) ) { elem.style.position = "relative"; } var curElem = $( elem ), curOffset = curElem.offset(), curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0, curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0, props = { top: (options.top - curOffset.top) + curTop, left: (options.left - curOffset.left) + curLeft }; if ( 'using' in options ) { options.using.call( elem, props ); } else { curElem.css( props ); } }; $.fn.offset = function( options ) { var elem = this[ 0 ]; if ( !elem || !elem.ownerDocument ) { return null; } if ( options ) { return this.each(function() { $.offset.setOffset( this, options ); }); } return _offset.call( this ); }; } }( jQuery )); SABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.ui.draggable.js0000644000000000000000000007433612701006716027537 0ustar rootroot/* * jQuery UI Draggable 1.8.15 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Draggables * * Depends: * jquery.ui.core.js * jquery.ui.mouse.js * jquery.ui.widget.js */ (function( $, undefined ) { $.widget("ui.draggable", $.ui.mouse, { widgetEventPrefix: "drag", options: { addClasses: true, appendTo: "parent", axis: false, connectToSortable: false, containment: false, cursor: "auto", cursorAt: false, grid: false, handle: false, helper: "original", iframeFix: false, opacity: false, refreshPositions: false, revert: false, revertDuration: 500, scope: "default", scroll: true, scrollSensitivity: 20, scrollSpeed: 20, snap: false, snapMode: "both", snapTolerance: 20, stack: false, zIndex: false }, _create: function() { if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) this.element[0].style.position = 'relative'; (this.options.addClasses && this.element.addClass("ui-draggable")); (this.options.disabled && this.element.addClass("ui-draggable-disabled")); this._mouseInit(); }, destroy: function() { if(!this.element.data('draggable')) return; this.element .removeData("draggable") .unbind(".draggable") .removeClass("ui-draggable" + " ui-draggable-dragging" + " ui-draggable-disabled"); this._mouseDestroy(); return this; }, _mouseCapture: function(event) { var o = this.options; // among others, prevent a drag on a resizable-handle if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) return false; //Quit if we're not on a valid handle this.handle = this._getHandle(event); if (!this.handle) return false; $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { $('
') .css({ width: this.offsetWidth+"px", height: this.offsetHeight+"px", position: "absolute", opacity: "0.001", zIndex: 1000 }) .css($(this).offset()) .appendTo("body"); }); return true; }, _mouseStart: function(event) { var o = this.options; //Create and append the visible helper this.helper = this._createHelper(event); //Cache the helper size this._cacheHelperProportions(); //If ddmanager is used for droppables, set the global draggable if($.ui.ddmanager) $.ui.ddmanager.current = this; /* * - Position generation - * This block generates everything position related - it's the core of draggables. */ //Cache the margins of the original element this._cacheMargins(); //Store the helper's css position this.cssPosition = this.helper.css("position"); this.scrollParent = this.helper.scrollParent(); //The element's absolute position on the page minus margins this.offset = this.positionAbs = this.element.offset(); this.offset = { top: this.offset.top - this.margins.top, left: this.offset.left - this.margins.left }; $.extend(this.offset, { click: { //Where the click happened, relative to the element left: event.pageX - this.offset.left, top: event.pageY - this.offset.top }, parent: this._getParentOffset(), relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper }); //Generate the original position this.originalPosition = this.position = this._generatePosition(event); this.originalPageX = event.pageX; this.originalPageY = event.pageY; //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); //Set a containment if given in the options if(o.containment) this._setContainment(); //Trigger event + callbacks if(this._trigger("start", event) === false) { this._clear(); return false; } //Recache the helper size this._cacheHelperProportions(); //Prepare the droppable offsets if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, event); this.helper.addClass("ui-draggable-dragging"); this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event); return true; }, _mouseDrag: function(event, noPropagation) { //Compute the helpers position this.position = this._generatePosition(event); this.positionAbs = this._convertPositionTo("absolute"); //Call plugins and callbacks and use the resulting position if something is returned if (!noPropagation) { var ui = this._uiHash(); if(this._trigger('drag', event, ui) === false) { this._mouseUp({}); return false; } this.position = ui.position; } if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); return false; }, _mouseStop: function(event) { //If we are using droppables, inform the manager about the drop var dropped = false; if ($.ui.ddmanager && !this.options.dropBehaviour) dropped = $.ui.ddmanager.drop(this, event); //if a drop comes from outside (a sortable) if(this.dropped) { dropped = this.dropped; this.dropped = false; } //if the original element is removed, don't bother to continue if helper is set to "original" if((!this.element[0] || !this.element[0].parentNode) && this.options.helper == "original") return false; if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { var self = this; $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { if(self._trigger("stop", event) !== false) { self._clear(); } }); } else { if(this._trigger("stop", event) !== false) { this._clear(); } } return false; }, _mouseUp: function(event) { if (this.options.iframeFix === true) { $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers } //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event); return $.ui.mouse.prototype._mouseUp.call(this, event); }, cancel: function() { if(this.helper.is(".ui-draggable-dragging")) { this._mouseUp({}); } else { this._clear(); } return this; }, _getHandle: function(event) { var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; $(this.options.handle, this.element) .find("*") .andSelf() .each(function() { if(this == event.target) handle = true; }); return handle; }, _createHelper: function(event) { var o = this.options; var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element); if(!helper.parents('body').length) helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) helper.css("position", "absolute"); return helper; }, _adjustOffsetFromHelper: function(obj) { if (typeof obj == 'string') { obj = obj.split(' '); } if ($.isArray(obj)) { obj = {left: +obj[0], top: +obj[1] || 0}; } if ('left' in obj) { this.offset.click.left = obj.left + this.margins.left; } if ('right' in obj) { this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; } if ('top' in obj) { this.offset.click.top = obj.top + this.margins.top; } if ('bottom' in obj) { this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; } }, _getParentOffset: function() { //Get the offsetParent and cache its position this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset(); // This is a special case where we need to modify a offset calculated on start, since the following happened: // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { po.left += this.scrollParent.scrollLeft(); po.top += this.scrollParent.scrollTop(); } if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix po = { top: 0, left: 0 }; return { top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) }; }, _getRelativeOffset: function() { if(this.cssPosition == "relative") { var p = this.element.position(); return { top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() }; } else { return { top: 0, left: 0 }; } }, _cacheMargins: function() { this.margins = { left: (parseInt(this.element.css("marginLeft"),10) || 0), top: (parseInt(this.element.css("marginTop"),10) || 0), right: (parseInt(this.element.css("marginRight"),10) || 0), bottom: (parseInt(this.element.css("marginBottom"),10) || 0) }; }, _cacheHelperProportions: function() { this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; }, _setContainment: function() { var o = this.options; if(o.containment == 'parent') o.containment = this.helper[0].parentNode; if(o.containment == 'document' || o.containment == 'window') this.containment = [ o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top ]; if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { var c = $(o.containment); var ce = c[0]; if(!ce) return; var co = c.offset(); var over = ($(ce).css("overflow") != 'hidden'); this.containment = [ (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom ]; this.relative_container = c; } else if(o.containment.constructor == Array) { this.containment = o.containment; } }, _convertPositionTo: function(d, pos) { if(!pos) pos = this.position; var mod = d == "absolute" ? 1 : -1; var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); return { top: ( pos.top // The absolute mouse position + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) ), left: ( pos.left // The absolute mouse position + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) ) }; }, _generatePosition: function(event) { var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); var pageX = event.pageX; var pageY = event.pageY; /* * - Position constraining - * Constrain the position to a mix of grid, containment. */ if(this.originalPosition) { //If we are not dragging yet, we won't check for options var containment; if(this.containment) { if (this.relative_container){ var co = this.relative_container.offset(); containment = [ this.containment[0] + co.left, this.containment[1] + co.top, this.containment[2] + co.left, this.containment[3] + co.top ]; } else { containment = this.containment; } if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left; if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top; if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left; if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top; } if(o.grid) { //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; } } return { top: ( pageY // The absolute mouse position - this.offset.click.top // Click offset (relative to the element) - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top // The offsetParent's offset without borders (offset + border) + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) ), left: ( pageX // The absolute mouse position - this.offset.click.left // Click offset (relative to the element) - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left // The offsetParent's offset without borders (offset + border) + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) ) }; }, _clear: function() { this.helper.removeClass("ui-draggable-dragging"); if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); //if($.ui.ddmanager) $.ui.ddmanager.current = null; this.helper = null; this.cancelHelperRemoval = false; }, // From now on bulk stuff - mainly helpers _trigger: function(type, event, ui) { ui = ui || this._uiHash(); $.ui.plugin.call(this, type, [event, ui]); if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins return $.Widget.prototype._trigger.call(this, type, event, ui); }, plugins: {}, _uiHash: function(event) { return { helper: this.helper, position: this.position, originalPosition: this.originalPosition, offset: this.positionAbs }; } }); $.extend($.ui.draggable, { version: "1.8.15" }); $.ui.plugin.add("draggable", "connectToSortable", { start: function(event, ui) { var inst = $(this).data("draggable"), o = inst.options, uiSortable = $.extend({}, ui, { item: inst.element }); inst.sortables = []; $(o.connectToSortable).each(function() { var sortable = $.data(this, 'sortable'); if (sortable && !sortable.options.disabled) { inst.sortables.push({ instance: sortable, shouldRevert: sortable.options.revert }); sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). sortable._trigger("activate", event, uiSortable); } }); }, stop: function(event, ui) { //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper var inst = $(this).data("draggable"), uiSortable = $.extend({}, ui, { item: inst.element }); $.each(inst.sortables, function() { if(this.instance.isOver) { this.instance.isOver = 0; inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' if(this.shouldRevert) this.instance.options.revert = true; //Trigger the stop of the sortable this.instance._mouseStop(event); this.instance.options.helper = this.instance.options._helper; //If the helper has been the original item, restore properties in the sortable if(inst.options.helper == 'original') this.instance.currentItem.css({ top: 'auto', left: 'auto' }); } else { this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance this.instance._trigger("deactivate", event, uiSortable); } }); }, drag: function(event, ui) { var inst = $(this).data("draggable"), self = this; var checkPos = function(o) { var dyClick = this.offset.click.top, dxClick = this.offset.click.left; var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; var itemHeight = o.height, itemWidth = o.width; var itemTop = o.top, itemLeft = o.left; return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); }; $.each(inst.sortables, function(i) { //Copy over some variables to allow calling the sortable's native _intersectsWith this.instance.positionAbs = inst.positionAbs; this.instance.helperProportions = inst.helperProportions; this.instance.offset.click = inst.offset.click; if(this.instance._intersectsWith(this.instance.containerCache)) { //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once if(!this.instance.isOver) { this.instance.isOver = 1; //Now we fake the start of dragging for the sortable instance, //by cloning the list group item, appending it to the sortable and using it as inst.currentItem //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) this.instance.currentItem = $(self).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true); this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it this.instance.options.helper = function() { return ui.helper[0]; }; event.target = this.instance.currentItem[0]; this.instance._mouseCapture(event, true); this.instance._mouseStart(event, true, true); //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes this.instance.offset.click.top = inst.offset.click.top; this.instance.offset.click.left = inst.offset.click.left; this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; inst._trigger("toSortable", event); inst.dropped = this.instance.element; //draggable revert needs that //hack so receive/update callbacks work (mostly) inst.currentItem = inst.element; this.instance.fromOutside = inst; } //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable if(this.instance.currentItem) this.instance._mouseDrag(event); } else { //If it doesn't intersect with the sortable, and it intersected before, //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval if(this.instance.isOver) { this.instance.isOver = 0; this.instance.cancelHelperRemoval = true; //Prevent reverting on this forced stop this.instance.options.revert = false; // The out event needs to be triggered independently this.instance._trigger('out', event, this.instance._uiHash(this.instance)); this.instance._mouseStop(event, true); this.instance.options.helper = this.instance.options._helper; //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size this.instance.currentItem.remove(); if(this.instance.placeholder) this.instance.placeholder.remove(); inst._trigger("fromSortable", event); inst.dropped = false; //draggable revert needs that } }; }); } }); $.ui.plugin.add("draggable", "cursor", { start: function(event, ui) { var t = $('body'), o = $(this).data('draggable').options; if (t.css("cursor")) o._cursor = t.css("cursor"); t.css("cursor", o.cursor); }, stop: function(event, ui) { var o = $(this).data('draggable').options; if (o._cursor) $('body').css("cursor", o._cursor); } }); $.ui.plugin.add("draggable", "opacity", { start: function(event, ui) { var t = $(ui.helper), o = $(this).data('draggable').options; if(t.css("opacity")) o._opacity = t.css("opacity"); t.css('opacity', o.opacity); }, stop: function(event, ui) { var o = $(this).data('draggable').options; if(o._opacity) $(ui.helper).css('opacity', o._opacity); } }); $.ui.plugin.add("draggable", "scroll", { start: function(event, ui) { var i = $(this).data("draggable"); if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); }, drag: function(event, ui) { var i = $(this).data("draggable"), o = i.options, scrolled = false; if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { if(!o.axis || o.axis != 'x') { if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; } if(!o.axis || o.axis != 'y') { if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; } } else { if(!o.axis || o.axis != 'x') { if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); } if(!o.axis || o.axis != 'y') { if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); } } if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(i, event); } }); $.ui.plugin.add("draggable", "snap", { start: function(event, ui) { var i = $(this).data("draggable"), o = i.options; i.snapElements = []; $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { var $t = $(this); var $o = $t.offset(); if(this != i.element[0]) i.snapElements.push({ item: this, width: $t.outerWidth(), height: $t.outerHeight(), top: $o.top, left: $o.left }); }); }, drag: function(event, ui) { var inst = $(this).data("draggable"), o = inst.options; var d = o.snapTolerance; var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; for (var i = inst.snapElements.length - 1; i >= 0; i--){ var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; //Yes, I know, this is insane ;) if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); inst.snapElements[i].snapping = false; continue; } if(o.snapMode != 'inner') { var ts = Math.abs(t - y2) <= d; var bs = Math.abs(b - y1) <= d; var ls = Math.abs(l - x2) <= d; var rs = Math.abs(r - x1) <= d; if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; } var first = (ts || bs || ls || rs); if(o.snapMode != 'outer') { var ts = Math.abs(t - y1) <= d; var bs = Math.abs(b - y2) <= d; var ls = Math.abs(l - x1) <= d; var rs = Math.abs(r - x2) <= d; if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; } if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); inst.snapElements[i].snapping = (ts || bs || ls || rs || first); }; } }); $.ui.plugin.add("draggable", "stack", { start: function(event, ui) { var o = $(this).data("draggable").options; var group = $.makeArray($(o.stack)).sort(function(a,b) { return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); }); if (!group.length) { return; } var min = parseInt(group[0].style.zIndex) || 0; $(group).each(function(i) { this.style.zIndex = min + i; }); this[0].style.zIndex = min + group.length; } }); $.ui.plugin.add("draggable", "zIndex", { start: function(event, ui) { var t = $(ui.helper), o = $(this).data("draggable").options; if(t.css("zIndex")) o._zIndex = t.css("zIndex"); t.css('zIndex', o.zIndex); }, stop: function(event, ui) { var o = $(this).data("draggable").options; if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); } }); })(jQuery); SABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.cookie_1.0.js0000644000000000000000000000720112701006716027025 0ustar rootroot/*jslint browser: true */ /*global jQuery: true */ /** * jQuery Cookie plugin * * Copyright (c) 2010 Klaus Hartl (stilbuero.de) * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * */ // TODO JsDoc /** * Create a cookie with the given key and value and other optional parameters. * * @example $.cookie('the_cookie', 'the_value'); * @desc Set the value of a cookie. * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); * @desc Create a cookie with all available options. * @example $.cookie('the_cookie', 'the_value'); * @desc Create a session cookie. * @example $.cookie('the_cookie', null); * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain * used when the cookie was set. * * @param String key The key of the cookie. * @param String value The value of the cookie. * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. * If set to null or omitted, the cookie will be a session cookie and will not be retained * when the the browser exits. * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will * require a secure protocol (like HTTPS). * @type undefined * * @name $.cookie * @cat Plugins/Cookie * @author Klaus Hartl/klaus.hartl@stilbuero.de */ /** * Get the value of a cookie with the given key. * * @example $.cookie('the_cookie'); * @desc Get the value of a cookie. * * @param String key The key of the cookie. * @return The value of the cookie. * @type String * * @name $.cookie * @cat Plugins/Cookie * @author Klaus Hartl/klaus.hartl@stilbuero.de */ jQuery.cookie = function (key, value, options) { // key and at least value given, set cookie... if (arguments.length > 1 && String(value) !== "[object Object]") { options = jQuery.extend({}, options); if (value === null || value === undefined) { options.expires = -1; } if (typeof options.expires === 'number') { var days = options.expires, t = options.expires = new Date(); t.setDate(t.getDate() + days); } value = String(value); return (document.cookie = [ encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value), options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE options.path ? '; path=' + options.path : '', options.domain ? '; domain=' + options.domain : '', options.secure ? '; secure' : '' ].join('')); } // key and possibly options given, get cookie... options = value || {}; var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent; return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null; }; SABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.ui.button.js0000644000000000000000000002605312701006716027133 0ustar rootroot/* * jQuery UI Button 1.8.15 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Button * * Depends: * jquery.ui.core.js * jquery.ui.widget.js */ (function( $, undefined ) { var lastActive, startXPos, startYPos, clickDragged, baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", stateClasses = "ui-state-hover ui-state-active ", typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", formResetHandler = function() { var buttons = $( this ).find( ":ui-button" ); setTimeout(function() { buttons.button( "refresh" ); }, 1 ); }, radioGroup = function( radio ) { var name = radio.name, form = radio.form, radios = $( [] ); if ( name ) { if ( form ) { radios = $( form ).find( "[name='" + name + "']" ); } else { radios = $( "[name='" + name + "']", radio.ownerDocument ) .filter(function() { return !this.form; }); } } return radios; }; $.widget( "ui.button", { options: { disabled: null, text: true, label: null, icons: { primary: null, secondary: null } }, _create: function() { this.element.closest( "form" ) .unbind( "reset.button" ) .bind( "reset.button", formResetHandler ); if ( typeof this.options.disabled !== "boolean" ) { this.options.disabled = this.element.propAttr( "disabled" ); } this._determineButtonType(); this.hasTitle = !!this.buttonElement.attr( "title" ); var self = this, options = this.options, toggleButton = this.type === "checkbox" || this.type === "radio", hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ), focusClass = "ui-state-focus"; if ( options.label === null ) { options.label = this.buttonElement.html(); } if ( this.element.is( ":disabled" ) ) { options.disabled = true; } this.buttonElement .addClass( baseClasses ) .attr( "role", "button" ) .bind( "mouseenter.button", function() { if ( options.disabled ) { return; } $( this ).addClass( "ui-state-hover" ); if ( this === lastActive ) { $( this ).addClass( "ui-state-active" ); } }) .bind( "mouseleave.button", function() { if ( options.disabled ) { return; } $( this ).removeClass( hoverClass ); }) .bind( "click.button", function( event ) { if ( options.disabled ) { event.preventDefault(); event.stopImmediatePropagation(); } }); this.element .bind( "focus.button", function() { // no need to check disabled, focus won't be triggered anyway self.buttonElement.addClass( focusClass ); }) .bind( "blur.button", function() { self.buttonElement.removeClass( focusClass ); }); if ( toggleButton ) { this.element.bind( "change.button", function() { if ( clickDragged ) { return; } self.refresh(); }); // if mouse moves between mousedown and mouseup (drag) set clickDragged flag // prevents issue where button state changes but checkbox/radio checked state // does not in Firefox (see ticket #6970) this.buttonElement .bind( "mousedown.button", function( event ) { if ( options.disabled ) { return; } clickDragged = false; startXPos = event.pageX; startYPos = event.pageY; }) .bind( "mouseup.button", function( event ) { if ( options.disabled ) { return; } if ( startXPos !== event.pageX || startYPos !== event.pageY ) { clickDragged = true; } }); } if ( this.type === "checkbox" ) { this.buttonElement.bind( "click.button", function() { if ( options.disabled || clickDragged ) { return false; } $( this ).toggleClass( "ui-state-active" ); self.buttonElement.attr( "aria-pressed", self.element[0].checked ); }); } else if ( this.type === "radio" ) { this.buttonElement.bind( "click.button", function() { if ( options.disabled || clickDragged ) { return false; } $( this ).addClass( "ui-state-active" ); self.buttonElement.attr( "aria-pressed", "true" ); var radio = self.element[ 0 ]; radioGroup( radio ) .not( radio ) .map(function() { return $( this ).button( "widget" )[ 0 ]; }) .removeClass( "ui-state-active" ) .attr( "aria-pressed", "false" ); }); } else { this.buttonElement .bind( "mousedown.button", function() { if ( options.disabled ) { return false; } $( this ).addClass( "ui-state-active" ); lastActive = this; $( document ).one( "mouseup", function() { lastActive = null; }); }) .bind( "mouseup.button", function() { if ( options.disabled ) { return false; } $( this ).removeClass( "ui-state-active" ); }) .bind( "keydown.button", function(event) { if ( options.disabled ) { return false; } if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) { $( this ).addClass( "ui-state-active" ); } }) .bind( "keyup.button", function() { $( this ).removeClass( "ui-state-active" ); }); if ( this.buttonElement.is("a") ) { this.buttonElement.keyup(function(event) { if ( event.keyCode === $.ui.keyCode.SPACE ) { // TODO pass through original event correctly (just as 2nd argument doesn't work) $( this ).click(); } }); } } // TODO: pull out $.Widget's handling for the disabled option into // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can // be overridden by individual plugins this._setOption( "disabled", options.disabled ); this._resetButton(); }, _determineButtonType: function() { if ( this.element.is(":checkbox") ) { this.type = "checkbox"; } else if ( this.element.is(":radio") ) { this.type = "radio"; } else if ( this.element.is("input") ) { this.type = "input"; } else { this.type = "button"; } if ( this.type === "checkbox" || this.type === "radio" ) { // we don't search against the document in case the element // is disconnected from the DOM var ancestor = this.element.parents().filter(":last"), labelSelector = "label[for=" + this.element.attr("id") + "]"; this.buttonElement = ancestor.find( labelSelector ); if ( !this.buttonElement.length ) { ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); this.buttonElement = ancestor.filter( labelSelector ); if ( !this.buttonElement.length ) { this.buttonElement = ancestor.find( labelSelector ); } } this.element.addClass( "ui-helper-hidden-accessible" ); var checked = this.element.is( ":checked" ); if ( checked ) { this.buttonElement.addClass( "ui-state-active" ); } this.buttonElement.attr( "aria-pressed", checked ); } else { this.buttonElement = this.element; } }, widget: function() { return this.buttonElement; }, destroy: function() { this.element .removeClass( "ui-helper-hidden-accessible" ); this.buttonElement .removeClass( baseClasses + " " + stateClasses + " " + typeClasses ) .removeAttr( "role" ) .removeAttr( "aria-pressed" ) .html( this.buttonElement.find(".ui-button-text").html() ); if ( !this.hasTitle ) { this.buttonElement.removeAttr( "title" ); } $.Widget.prototype.destroy.call( this ); }, _setOption: function( key, value ) { $.Widget.prototype._setOption.apply( this, arguments ); if ( key === "disabled" ) { if ( value ) { this.element.propAttr( "disabled", true ); } else { this.element.propAttr( "disabled", false ); } return; } this._resetButton(); }, refresh: function() { var isDisabled = this.element.is( ":disabled" ); if ( isDisabled !== this.options.disabled ) { this._setOption( "disabled", isDisabled ); } if ( this.type === "radio" ) { radioGroup( this.element[0] ).each(function() { if ( $( this ).is( ":checked" ) ) { $( this ).button( "widget" ) .addClass( "ui-state-active" ) .attr( "aria-pressed", "true" ); } else { $( this ).button( "widget" ) .removeClass( "ui-state-active" ) .attr( "aria-pressed", "false" ); } }); } else if ( this.type === "checkbox" ) { if ( this.element.is( ":checked" ) ) { this.buttonElement .addClass( "ui-state-active" ) .attr( "aria-pressed", "true" ); } else { this.buttonElement .removeClass( "ui-state-active" ) .attr( "aria-pressed", "false" ); } } }, _resetButton: function() { if ( this.type === "input" ) { if ( this.options.label ) { this.element.val( this.options.label ); } return; } var buttonElement = this.buttonElement.removeClass( typeClasses ), buttonText = $( "" ) .addClass( "ui-button-text" ) .html( this.options.label ) .appendTo( buttonElement.empty() ) .text(), icons = this.options.icons, multipleIcons = icons.primary && icons.secondary, buttonClasses = []; if ( icons.primary || icons.secondary ) { if ( this.options.text ) { buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); } if ( icons.primary ) { buttonElement.prepend( "" ); } if ( icons.secondary ) { buttonElement.append( "" ); } if ( !this.options.text ) { buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); if ( !this.hasTitle ) { buttonElement.attr( "title", buttonText ); } } } else { buttonClasses.push( "ui-button-text-only" ); } buttonElement.addClass( buttonClasses.join( " " ) ); } }); $.widget( "ui.buttonset", { options: { items: ":button, :submit, :reset, :checkbox, :radio, a, :data(button)" }, _create: function() { this.element.addClass( "ui-buttonset" ); }, _init: function() { this.refresh(); }, _setOption: function( key, value ) { if ( key === "disabled" ) { this.buttons.button( "option", key, value ); } $.Widget.prototype._setOption.apply( this, arguments ); }, refresh: function() { var ltr = this.element.css( "direction" ) === "ltr"; this.buttons = this.element.find( this.options.items ) .filter( ":ui-button" ) .button( "refresh" ) .end() .not( ":ui-button" ) .button() .end() .map(function() { return $( this ).button( "widget" )[ 0 ]; }) .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) .filter( ":first" ) .addClass( ltr ? "ui-corner-left" : "ui-corner-right" ) .end() .filter( ":last" ) .addClass( ltr ? "ui-corner-right" : "ui-corner-left" ) .end() .end(); }, destroy: function() { this.element.removeClass( "ui-buttonset" ); this.buttons .map(function() { return $( this ).button( "widget" )[ 0 ]; }) .removeClass( "ui-corner-left ui-corner-right" ) .end() .button( "destroy" ); $.Widget.prototype.destroy.call( this ); } }); }( jQuery ) ); SABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/lib.js0000777000000000000000000000000013224674740025314 2READMEustar rootrootSABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.rateit.js0000644000000000000000000003476312701006716026503 0ustar rootroot/* RateIt version 1.0.13 08/17/2013 http://rateit.codeplex.com Twitter: @gjunge */ (function ($) { $.rateit = { aria : { resetLabel: 'reset rating', ratingLabel: 'rating' } } $.fn.rateit = function (p1, p2) { //quick way out. var index = 1; var options = {}; var mode = 'init'; var capitaliseFirstLetter = function (string) { return string.charAt(0).toUpperCase() + string.substr(1); }; if (this.length == 0) return this; var tp1 = $.type(p1); if (tp1 == 'object' || p1 === undefined || p1 == null) { options = $.extend({}, $.fn.rateit.defaults, p1); //wants to init new rateit plugin(s). } else if (tp1 == 'string' && p2 === undefined) { return this.data('rateit' + capitaliseFirstLetter(p1)); //wants to get a value. } else if (tp1 == 'string') { mode = 'setvalue' } return this.each(function () { var item = $(this); //shorten all the item.data('rateit-XXX'), will save space in closure compiler, will be like item.data('XXX') will become x('XXX') var itemdata = function (key, value) { if (value != null) { //update aria values var ariakey = 'aria-value' + ((key == 'value') ? 'now' : key); var range = item.find('.rateit-range'); if (range.attr(ariakey) != undefined) { range.attr(ariakey, value); } } arguments[0] = 'rateit' + capitaliseFirstLetter(key); return item.data.apply(item, arguments); ////Fix for WI: 523 }; //add the rate it class. if (!item.hasClass('rateit')) item.addClass('rateit'); var ltr = item.css('direction') != 'rtl'; // set value mode if (mode == 'setvalue') { if (!itemdata('init')) throw 'Can\'t set value before init'; //if readonly now and it wasn't readonly, remove the eventhandlers. if (p1 == 'readonly' && p2 == true && !itemdata('readonly')) { item.find('.rateit-range').unbind(); itemdata('wired', false); } //when we receive a null value, reset the score to its min value. if (p1 == 'value') p2 = (p2 == null) ? itemdata('min') : Math.max(itemdata('min'), Math.min(itemdata('max'), p2)); if (itemdata('backingfld')) { //if we have a backing field, check which fields we should update. //In case of input[type=range], although we did read its attributes even in browsers that don't support it (using fld.attr()) //we only update it in browser that support it (&& fld[0].min only works in supporting browsers), not only does it save us from checking if it is range input type, it also is unnecessary. var fld = $(itemdata('backingfld')); if (p1 == 'value') fld.val(p2); if (p1 == 'min' && fld[0].min) fld[0].min = p2; if (p1 == 'max' && fld[0].max) fld[0].max = p2; if (p1 == 'step' && fld[0].step) fld[0].step = p2; } itemdata(p1, p2); } //init rateit plugin if (!itemdata('init')) { //get our values, either from the data-* html5 attribute or from the options. itemdata('min', itemdata('min') || options.min); itemdata('max', itemdata('max') || options.max); itemdata('step', itemdata('step') || options.step); itemdata('readonly', itemdata('readonly') !== undefined ? itemdata('readonly') : options.readonly); itemdata('resetable', itemdata('resetable') !== undefined ? itemdata('resetable') : options.resetable); itemdata('backingfld', itemdata('backingfld') || options.backingfld); itemdata('starwidth', itemdata('starwidth') || options.starwidth); itemdata('starheight', itemdata('starheight') || options.starheight); itemdata('value', Math.max(itemdata('min'), Math.min(itemdata('max'), (itemdata('value') || options.value || options.min) ))); itemdata('ispreset', itemdata('ispreset') !== undefined ? itemdata('ispreset') : options.ispreset); //are we LTR or RTL? if (itemdata('backingfld')) { //if we have a backing field, hide it, and get its value, and override defaults if range. var fld = $(itemdata('backingfld')); itemdata('value', fld.hide().val()); if (fld.attr('disabled') || fld.attr('readonly')) itemdata('readonly', true); //http://rateit.codeplex.com/discussions/362055 , if a backing field is disabled or readonly at instantiation, make rateit readonly. if (fld[0].nodeName == 'INPUT') { if (fld[0].type == 'range' || fld[0].type == 'text') { //in browsers not support the range type, it defaults to text itemdata('min', parseInt(fld.attr('min')) || itemdata('min')); //if we would have done fld[0].min it wouldn't have worked in browsers not supporting the range type. itemdata('max', parseInt(fld.attr('max')) || itemdata('max')); itemdata('step', parseInt(fld.attr('step')) || itemdata('step')); } } if (fld[0].nodeName == 'SELECT' && fld[0].options.length > 1) { itemdata('min', Number(fld[0].options[0].value)); itemdata('max', Number(fld[0].options[fld[0].length - 1].value)); itemdata('step', Number(fld[0].options[1].value) - Number(fld[0].options[0].value)); } } //Create the necessary tags. For ARIA purposes we need to give the items an ID. So we use an internal index to create unique ids var element = item[0].nodeName == 'DIV' ? 'div' : 'span'; index++; var html = '<{{element}} id="rateit-range-{{index}}" class="rateit-range" tabindex="0" role="slider" aria-label="' + $.rateit.aria.ratingLabel + '" aria-owns="rateit-reset-{{index}}" aria-valuemin="' + itemdata('min') + '" aria-valuemax="' + itemdata('max') + '" aria-valuenow="' + itemdata('value') + '"><{{element}} class="rateit-selected" style="height:' + itemdata('starheight') + 'px"><{{element}} class="rateit-hover" style="height:' + itemdata('starheight') + 'px">'; item.append(html.replace(/{{index}}/gi, index).replace(/{{element}}/gi, element)); //if we are in RTL mode, we have to change the float of the "reset button" if (!ltr) { item.find('.rateit-reset').css('float', 'right'); item.find('.rateit-selected').addClass('rateit-selected-rtl'); item.find('.rateit-hover').addClass('rateit-hover-rtl'); } itemdata('init', true); } //set the range element to fit all the stars. var range = item.find('.rateit-range'); range.width(itemdata('starwidth') * (itemdata('max') - itemdata('min'))).height(itemdata('starheight')); //add/remove the preset class var presetclass = 'rateit-preset' + ((ltr) ? '' : '-rtl'); if (itemdata('ispreset')) item.find('.rateit-selected').addClass(presetclass); else item.find('.rateit-selected').removeClass(presetclass); //set the value if we have it. if (itemdata('value') != null) { var score = (itemdata('value') - itemdata('min')) * itemdata('starwidth'); item.find('.rateit-selected').width(score); } //setup the reset button var resetbtn = item.find('.rateit-reset'); if (resetbtn.data('wired') !== true) { resetbtn.bind('click', function (e) { e.preventDefault(); resetbtn.blur(); itemdata('value', itemdata('min')); range.find('.rateit-hover').hide().width(0); range.find('.rateit-selected').width(0).show(); if (itemdata('backingfld')) $(itemdata('backingfld')).val(itemdata('min')); item.trigger('reset'); }).data('wired', true); } //this function calculates the score based on the current position of the mouse. var calcRawScore = function (element, event) { var pageX = (event.changedTouches) ? event.changedTouches[0].pageX : event.pageX; var offsetx = pageX - $(element).offset().left; if (!ltr) offsetx = range.width() - offsetx; if (offsetx > range.width()) offsetx = range.width(); if (offsetx < 0) offsetx = 0; return score = Math.ceil(offsetx / itemdata('starwidth') * (1 / itemdata('step'))); }; //sets the hover element based on the score. var setHover = function (score) { var w = score * itemdata('starwidth') * itemdata('step'); var h = range.find('.rateit-hover'); if (h.data('width') != w) { range.find('.rateit-selected').hide(); h.width(w).show().data('width', w); var data = [(score * itemdata('step')) + itemdata('min')]; item.trigger('hover', data).trigger('over', data); } }; var setSelection = function (value) { itemdata('value', value); if (itemdata('backingfld')) { $(itemdata('backingfld')).val(value); } if (itemdata('ispreset')) { //if it was a preset value, unset that. range.find('.rateit-selected').removeClass(presetclass); itemdata('ispreset', false); } range.find('.rateit-hover').hide(); range.find('.rateit-selected').width(value * itemdata('starwidth') - (itemdata('min') * itemdata('starwidth'))).show(); item.trigger('hover', [null]).trigger('over', [null]).trigger('rated', [value]); }; if (!itemdata('readonly')) { //if we are not read only, add all the events //if we have a reset button, set the event handler. if (!itemdata('resetable')) resetbtn.hide(); //when the mouse goes over the range element, we set the "hover" stars. if (!itemdata('wired')) { range.bind('touchmove touchend', touchHandler); //bind touch events range.mousemove(function (e) { var score = calcRawScore(this, e); setHover(score); }); //when the mouse leaves the range, we have to hide the hover stars, and show the current value. range.mouseleave(function (e) { range.find('.rateit-hover').hide().width(0).data('width', ''); item.trigger('hover', [null]).trigger('over', [null]); range.find('.rateit-selected').show(); }); //when we click on the range, we have to set the value, hide the hover. range.mouseup(function (e) { var score = calcRawScore(this, e); var value = (score * itemdata('step')) + itemdata('min'); setSelection(value); }); //support key nav range.keyup( function (e) { if (e.which == 38 || e.which == (ltr ? 39 : 37)) { setSelection(Math.min(itemdata('value') + itemdata('step'), itemdata('max'))); } if (e.which == 40 || e.which == (ltr ? 37 : 39)) { setSelection(Math.max(itemdata('value') - itemdata('step'), itemdata('min'))); } }); itemdata('wired', true); } if (itemdata('resetable')) { resetbtn.show(); } } else { resetbtn.hide(); } range.attr('aria-readonly', itemdata('readonly')); }); }; //touch converter http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/ function touchHandler(event) { var touches = event.originalEvent.changedTouches, first = touches[0], type = ""; switch (event.type) { case "touchmove": type = "mousemove"; break; case "touchend": type = "mouseup"; break; default: return; } var simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0/*left*/, null); first.target.dispatchEvent(simulatedEvent); event.preventDefault(); }; //some default values. $.fn.rateit.defaults = { min: 0, max: 5, step: 0.5, starwidth: 16, starheight: 16, readonly: false, resetable: true, ispreset: false}; //invoke it on all .rateit elements. This could be removed if not wanted. $(function () { $('div.rateit, span.rateit').rateit(); }); })(jQuery);SABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.hoverIntent.r5.js0000644000000000000000000001066212701006716030035 0ustar rootroot/** * hoverIntent is similar to jQuery's built-in "hover" function except that * instead of firing the onMouseOver event immediately, hoverIntent checks * to see if the user's mouse has slowed down (beneath the sensitivity * threshold) before firing the onMouseOver event. * * hoverIntent r5 // 2007.03.27 // jQuery 1.1.2+ * * * hoverIntent is currently available for use in all personal or commercial * projects under both MIT and GPL licenses. This means that you can choose * the license that best suits your project, and use it accordingly. * * // basic usage (just like .hover) receives onMouseOver and onMouseOut functions * $("ul li").hoverIntent( showNav , hideNav ); * * // advanced usage receives configuration object only * $("ul li").hoverIntent({ * sensitivity: 7, // number = sensitivity threshold (must be 1 or higher) * interval: 100, // number = milliseconds of polling interval * over: showNav, // function = onMouseOver callback (required) * timeout: 0, // number = milliseconds delay before onMouseOut function call * out: hideNav // function = onMouseOut callback (required) * }); * * @param f onMouseOver function || An object with configuration options * @param g onMouseOut function || Nothing (use configuration options object) * @author Brian Cherne */ (function($) { $.fn.hoverIntent = function(f,g) { // default configuration options var cfg = { sensitivity: 7, interval: 100, timeout: 0 }; // override configuration options with user supplied object cfg = $.extend(cfg, g ? { over: f, out: g } : f ); // instantiate variables // cX, cY = current X and Y position of mouse, updated by mousemove event // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval var cX, cY, pX, pY; // A private function for getting mouse position var track = function(ev) { cX = ev.pageX; cY = ev.pageY; }; // A private function for comparing current and previous mouse position var compare = function(ev,ob) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); // compare mouse positions to see if they've crossed the threshold if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) { $(ob).unbind("mousemove",track); // set hoverIntent state to true (so mouseOut can be called) ob.hoverIntent_s = 1; return cfg.over.apply(ob,[ev]); } else { // set previous coordinates for next time pX = cX; pY = cY; // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs) ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval ); } }; // A private function for delaying the mouseOut function var delay = function(ev,ob) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); ob.hoverIntent_s = 0; return cfg.out.apply(ob,[ev]); }; // A private function for handling mouse 'hovering' var handleHover = function(e) { // next three lines copied from jQuery.hover, ignore children onMouseOver/onMouseOut var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget; while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } } if ( p == this ) { return false; } // copy objects to be passed into t (required for event object to be passed in IE) var ev = jQuery.extend({},e); var ob = this; // cancel hoverIntent timer if it exists if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); } // else e.type == "onmouseover" if (e.type == "mouseover") { // set "previous" X and Y position based on initial entry point pX = ev.pageX; pY = ev.pageY; // update "current" X and Y position based on mousemove $(ob).bind("mousemove",track); // start polling interval (self-calling timeout) to compare mouse coordinates over time if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );} // else e.type == "onmouseout" } else { // unbind expensive mousemove event $(ob).unbind("mousemove",track); // if hoverIntent state is true, then call the mouseOut function after the specified delay if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );} } }; // bind the function to the two event listeners return this.mouseover(handleHover).mouseout(handleHover); }; })(jQuery); SABnzbd-2.3.2/interfaces/Plush/templates/static/javascripts/src/jquery.ui.resizable.js0000644000000000000000000006621312701006716027602 0ustar rootroot/* * jQuery UI Resizable 1.8.15 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Resizables * * Depends: * jquery.ui.core.js * jquery.ui.mouse.js * jquery.ui.widget.js */ (function( $, undefined ) { $.widget("ui.resizable", $.ui.mouse, { widgetEventPrefix: "resize", options: { alsoResize: false, animate: false, animateDuration: "slow", animateEasing: "swing", aspectRatio: false, autoHide: false, containment: false, ghost: false, grid: false, handles: "e,s,se", helper: false, maxHeight: null, maxWidth: null, minHeight: 10, minWidth: 10, zIndex: 1000 }, _create: function() { var self = this, o = this.options; this.element.addClass("ui-resizable"); $.extend(this, { _aspectRatio: !!(o.aspectRatio), aspectRatio: o.aspectRatio, originalElement: this.element, _proportionallyResizeElements: [], _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null }); //Wrap the element if it cannot hold child nodes if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { //Opera fix for relative positioning if (/relative/.test(this.element.css('position')) && $.browser.opera) this.element.css({ position: 'relative', top: 'auto', left: 'auto' }); //Create a wrapper element and set the wrapper to the new current internal element this.element.wrap( $('
').css({ position: this.element.css('position'), width: this.element.outerWidth(), height: this.element.outerHeight(), top: this.element.css('top'), left: this.element.css('left') }) ); //Overwrite the original this.element this.element = this.element.parent().data( "resizable", this.element.data('resizable') ); this.elementIsWrapper = true; //Move margins to the wrapper this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); //Prevent Safari textarea resize this.originalResizeStyle = this.originalElement.css('resize'); this.originalElement.css('resize', 'none'); //Push the actual element to our proportionallyResize internal array this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' })); // avoid IE jump (hard set the margin) this.originalElement.css({ margin: this.originalElement.css('margin') }); // fix handlers offset this._proportionallyResize(); } this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }); if(this.handles.constructor == String) { if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw'; var n = this.handles.split(","); this.handles = {}; for(var i = 0; i < n.length; i++) { var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle; var axis = $('
'); // increase zIndex of sw, se, ne, nw axis //TODO : this modifies original option if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex }); //TODO : What's going on here? if ('se' == handle) { axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se'); }; //Insert into internal handles object and append to element this.handles[handle] = '.ui-resizable-'+handle; this.element.append(axis); } } this._renderAxis = function(target) { target = target || this.element; for(var i in this.handles) { if(this.handles[i].constructor == String) this.handles[i] = $(this.handles[i], this.element).show(); //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { var axis = $(this.handles[i], this.element), padWrapper = 0; //Checking the correct pad and border padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); //The padding type i have to apply... var padPos = [ 'padding', /ne|nw|n/.test(i) ? 'Top' : /se|sw|s/.test(i) ? 'Bottom' : /^e$/.test(i) ? 'Right' : 'Left' ].join(""); target.css(padPos, padWrapper); this._proportionallyResize(); } //TODO: What's that good for? There's not anything to be executed left if(!$(this.handles[i]).length) continue; } }; //TODO: make renderAxis a prototype function this._renderAxis(this.element); this._handles = $('.ui-resizable-handle', this.element) .disableSelection(); //Matching axis name this._handles.mouseover(function() { if (!self.resizing) { if (this.className) var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); //Axis, default = se self.axis = axis && axis[1] ? axis[1] : 'se'; } }); //If we want to auto hide the elements if (o.autoHide) { this._handles.hide(); $(this.element) .addClass("ui-resizable-autohide") .hover(function() { if (o.disabled) return; $(this).removeClass("ui-resizable-autohide"); self._handles.show(); }, function(){ if (o.disabled) return; if (!self.resizing) { $(this).addClass("ui-resizable-autohide"); self._handles.hide(); } }); } //Initialize the mouse interaction this._mouseInit(); }, destroy: function() { this._mouseDestroy(); var _destroy = function(exp) { $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); }; //TODO: Unwrap at same DOM position if (this.elementIsWrapper) { _destroy(this.element); var wrapper = this.element; wrapper.after( this.originalElement.css({ position: wrapper.css('position'), width: wrapper.outerWidth(), height: wrapper.outerHeight(), top: wrapper.css('top'), left: wrapper.css('left') }) ).remove(); } this.originalElement.css('resize', this.originalResizeStyle); _destroy(this.originalElement); return this; }, _mouseCapture: function(event) { var handle = false; for (var i in this.handles) { if ($(this.handles[i])[0] == event.target) { handle = true; } } return !this.options.disabled && handle; }, _mouseStart: function(event) { var o = this.options, iniPos = this.element.position(), el = this.element; this.resizing = true; this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; // bugfix for http://dev.jquery.com/ticket/1749 if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left }); } //Opera fixing relative position if ($.browser.opera && (/relative/).test(el.css('position'))) el.css({ position: 'relative', top: 'auto', left: 'auto' }); this._renderProxy(); var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); if (o.containment) { curleft += $(o.containment).scrollLeft() || 0; curtop += $(o.containment).scrollTop() || 0; } //Store needed variables this.offset = this.helper.offset(); this.position = { left: curleft, top: curtop }; this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; this.originalPosition = { left: curleft, top: curtop }; this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; this.originalMousePosition = { left: event.pageX, top: event.pageY }; //Aspect Ratio this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); var cursor = $('.ui-resizable-' + this.axis).css('cursor'); $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); el.addClass("ui-resizable-resizing"); this._propagate("start", event); return true; }, _mouseDrag: function(event) { //Increase performance, avoid regex var el = this.helper, o = this.options, props = {}, self = this, smp = this.originalMousePosition, a = this.axis; var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; var trigger = this._change[a]; if (!trigger) return false; // Calculate the attrs that will be change var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff; // Put this in the mouseDrag handler since the user can start pressing shift while resizing this._updateVirtualBoundaries(event.shiftKey); if (this._aspectRatio || event.shiftKey) data = this._updateRatio(data, event); data = this._respectSize(data, event); // plugins callbacks need to be called first this._propagate("resize", event); el.css({ top: this.position.top + "px", left: this.position.left + "px", width: this.size.width + "px", height: this.size.height + "px" }); if (!this._helper && this._proportionallyResizeElements.length) this._proportionallyResize(); this._updateCache(data); // calling the user callback at the end this._trigger('resize', event, this.ui()); return false; }, _mouseStop: function(event) { this.resizing = false; var o = this.options, self = this; if(this._helper) { var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, soffsetw = ista ? 0 : self.sizeDiff.width; var s = { width: (self.helper.width() - soffsetw), height: (self.helper.height() - soffseth) }, left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; if (!o.animate) this.element.css($.extend(s, { top: top, left: left })); self.helper.height(self.size.height); self.helper.width(self.size.width); if (this._helper && !o.animate) this._proportionallyResize(); } $('body').css('cursor', 'auto'); this.element.removeClass("ui-resizable-resizing"); this._propagate("stop", event); if (this._helper) this.helper.remove(); return false; }, _updateVirtualBoundaries: function(forceAspectRatio) { var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b; b = { minWidth: isNumber(o.minWidth) ? o.minWidth : 0, maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, minHeight: isNumber(o.minHeight) ? o.minHeight : 0, maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity }; if(this._aspectRatio || forceAspectRatio) { // We want to create an enclosing box whose aspect ration is the requested one // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension pMinWidth = b.minHeight * this.aspectRatio; pMinHeight = b.minWidth / this.aspectRatio; pMaxWidth = b.maxHeight * this.aspectRatio; pMaxHeight = b.maxWidth / this.aspectRatio; if(pMinWidth > b.minWidth) b.minWidth = pMinWidth; if(pMinHeight > b.minHeight) b.minHeight = pMinHeight; if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth; if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight; } this._vBoundaries = b; }, _updateCache: function(data) { var o = this.options; this.offset = this.helper.offset(); if (isNumber(data.left)) this.position.left = data.left; if (isNumber(data.top)) this.position.top = data.top; if (isNumber(data.height)) this.size.height = data.height; if (isNumber(data.width)) this.size.width = data.width; }, _updateRatio: function(data, event) { var o = this.options, cpos = this.position, csize = this.size, a = this.axis; if (isNumber(data.height)) data.width = (data.height * this.aspectRatio); else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio); if (a == 'sw') { data.left = cpos.left + (csize.width - data.width); data.top = null; } if (a == 'nw') { data.top = cpos.top + (csize.height - data.height); data.left = cpos.left + (csize.width - data.width); } return data; }, _respectSize: function(data, event) { var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis, ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height); if (isminw) data.width = o.minWidth; if (isminh) data.height = o.minHeight; if (ismaxw) data.width = o.maxWidth; if (ismaxh) data.height = o.maxHeight; var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); if (isminw && cw) data.left = dw - o.minWidth; if (ismaxw && cw) data.left = dw - o.maxWidth; if (isminh && ch) data.top = dh - o.minHeight; if (ismaxh && ch) data.top = dh - o.maxHeight; // fixing jump error on top/left - bug #2330 var isNotwh = !data.width && !data.height; if (isNotwh && !data.left && data.top) data.top = null; else if (isNotwh && !data.top && data.left) data.left = null; return data; }, _proportionallyResize: function() { var o = this.options; if (!this._proportionallyResizeElements.length) return; var element = this.helper || this.element; for (var i=0; i < this._proportionallyResizeElements.length; i++) { var prel = this._proportionallyResizeElements[i]; if (!this.borderDif) { var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; this.borderDif = $.map(b, function(v, i) { var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; return border + padding; }); } if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length))) continue; prel.css({ height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 }); }; }, _renderProxy: function() { var el = this.element, o = this.options; this.elementOffset = el.offset(); if(this._helper) { this.helper = this.helper || $('
'); // fix ie6 offset TODO: This seems broken var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0), pxyoffset = ( ie6 ? 2 : -1 ); this.helper.addClass(this._helper).css({ width: this.element.outerWidth() + pxyoffset, height: this.element.outerHeight() + pxyoffset, position: 'absolute', left: this.elementOffset.left - ie6offset +'px', top: this.elementOffset.top - ie6offset +'px', zIndex: ++o.zIndex //TODO: Don't modify option }); this.helper .appendTo("body") .disableSelection(); } else { this.helper = this.element; } }, _change: { e: function(event, dx, dy) { return { width: this.originalSize.width + dx }; }, w: function(event, dx, dy) { var o = this.options, cs = this.originalSize, sp = this.originalPosition; return { left: sp.left + dx, width: cs.width - dx }; }, n: function(event, dx, dy) { var o = this.options, cs = this.originalSize, sp = this.originalPosition; return { top: sp.top + dy, height: cs.height - dy }; }, s: function(event, dx, dy) { return { height: this.originalSize.height + dy }; }, se: function(event, dx, dy) { return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); }, sw: function(event, dx, dy) { return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); }, ne: function(event, dx, dy) { return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); }, nw: function(event, dx, dy) { return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); } }, _propagate: function(n, event) { $.ui.plugin.call(this, n, [event, this.ui()]); (n != "resize" && this._trigger(n, event, this.ui())); }, plugins: {}, ui: function() { return { originalElement: this.originalElement, element: this.element, helper: this.helper, position: this.position, size: this.size, originalSize: this.originalSize, originalPosition: this.originalPosition }; } }); $.extend($.ui.resizable, { version: "1.8.15" }); /* * Resizable Extensions */ $.ui.plugin.add("resizable", "alsoResize", { start: function (event, ui) { var self = $(this).data("resizable"), o = self.options; var _store = function (exp) { $(exp).each(function() { var el = $(this); el.data("resizable-alsoresize", { width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10), position: el.css('position') // to reset Opera on stop() }); }); }; if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } else { $.each(o.alsoResize, function (exp) { _store(exp); }); } }else{ _store(o.alsoResize); } }, resize: function (event, ui) { var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition; var delta = { height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0, top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0 }, _alsoResize = function (exp, c) { $(exp).each(function() { var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left']; $.each(css, function (i, prop) { var sum = (start[prop]||0) + (delta[prop]||0); if (sum && sum >= 0) style[prop] = sum || null; }); // Opera fixing relative position if ($.browser.opera && /relative/.test(el.css('position'))) { self._revertToRelativePosition = true; el.css({ position: 'absolute', top: 'auto', left: 'auto' }); } el.css(style); }); }; if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); }else{ _alsoResize(o.alsoResize); } }, stop: function (event, ui) { var self = $(this).data("resizable"), o = self.options; var _reset = function (exp) { $(exp).each(function() { var el = $(this); // reset position for Opera - no need to verify it was changed el.css({ position: el.data("resizable-alsoresize").position }); }); }; if (self._revertToRelativePosition) { self._revertToRelativePosition = false; if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { $.each(o.alsoResize, function (exp) { _reset(exp); }); }else{ _reset(o.alsoResize); } } $(this).removeData("resizable-alsoresize"); } }); $.ui.plugin.add("resizable", "animate", { stop: function(event, ui) { var self = $(this).data("resizable"), o = self.options; var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, soffsetw = ista ? 0 : self.sizeDiff.width; var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; self.element.animate( $.extend(style, top && left ? { top: top, left: left } : {}), { duration: o.animateDuration, easing: o.animateEasing, step: function() { var data = { width: parseInt(self.element.css('width'), 10), height: parseInt(self.element.css('height'), 10), top: parseInt(self.element.css('top'), 10), left: parseInt(self.element.css('left'), 10) }; if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height }); // propagating resize, and updating values for each animation step self._updateCache(data); self._propagate("resize", event); } } ); } }); $.ui.plugin.add("resizable", "containment", { start: function(event, ui) { var self = $(this).data("resizable"), o = self.options, el = self.element; var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; if (!ce) return; self.containerElement = $(ce); if (/document/.test(oc) || oc == document) { self.containerOffset = { left: 0, top: 0 }; self.containerPosition = { left: 0, top: 0 }; self.parentData = { element: $(document), left: 0, top: 0, width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight }; } // i'm a node, so compute top, left, right, bottom else { var element = $(ce), p = []; $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); self.containerOffset = element.offset(); self.containerPosition = element.position(); self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width, width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); self.parentData = { element: ce, left: co.left, top: co.top, width: width, height: height }; } }, resize: function(event, ui) { var self = $(this).data("resizable"), o = self.options, ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position, pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement; if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co; if (cp.left < (self._helper ? co.left : 0)) { self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left)); if (pRatio) self.size.height = self.size.width / o.aspectRatio; self.position.left = o.helper ? co.left : 0; } if (cp.top < (self._helper ? co.top : 0)) { self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top); if (pRatio) self.size.width = self.size.height * o.aspectRatio; self.position.top = self._helper ? co.top : 0; } self.offset.left = self.parentData.left+self.position.left; self.offset.top = self.parentData.top+self.position.top; var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ), hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height ); var isParent = self.containerElement.get(0) == self.element.parent().get(0), isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position')); if(isParent && isOffsetRelative) woset -= self.parentData.left; if (woset + self.size.width >= self.parentData.width) { self.size.width = self.parentData.width - woset; if (pRatio) self.size.height = self.size.width / self.aspectRatio; } if (hoset + self.size.height >= self.parentData.height) { self.size.height = self.parentData.height - hoset; if (pRatio) self.size.width = self.size.height * self.aspectRatio; } }, stop: function(event, ui){ var self = $(this).data("resizable"), o = self.options, cp = self.position, co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement; var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height; if (self._helper && !o.animate && (/relative/).test(ce.css('position'))) $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); if (self._helper && !o.animate && (/static/).test(ce.css('position'))) $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); } }); $.ui.plugin.add("resizable", "ghost", { start: function(event, ui) { var self = $(this).data("resizable"), o = self.options, cs = self.size; self.ghost = self.originalElement.clone(); self.ghost .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) .addClass('ui-resizable-ghost') .addClass(typeof o.ghost == 'string' ? o.ghost : ''); self.ghost.appendTo(self.helper); }, resize: function(event, ui){ var self = $(this).data("resizable"), o = self.options; if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width }); }, stop: function(event, ui){ var self = $(this).data("resizable"), o = self.options; if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0)); } }); $.ui.plugin.add("resizable", "grid", { resize: function(event, ui) { var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey; o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); if (/^(se|s|e)$/.test(a)) { self.size.width = os.width + ox; self.size.height = os.height + oy; } else if (/^(ne)$/.test(a)) { self.size.width = os.width + ox; self.size.height = os.height + oy; self.position.top = op.top - oy; } else if (/^(sw)$/.test(a)) { self.size.width = os.width + ox; self.size.height = os.height + oy; self.position.left = op.left - ox; } else { self.size.width = os.width + ox; self.size.height = os.height + oy; self.position.top = op.top - oy; self.position.left = op.left - ox; } } }); var num = function(v) { return parseInt(v, 10) || 0; }; var isNumber = function(value) { return !isNaN(parseInt(value, 10)); }; })(jQuery); SABnzbd-2.3.2/interfaces/smpl/0000755000000000000000000000000013224674740014606 5ustar rootrootSABnzbd-2.3.2/interfaces/smpl/templates/0000755000000000000000000000000013224674740016604 5ustar rootrootSABnzbd-2.3.2/interfaces/smpl/templates/static/0000755000000000000000000000000013224674740020073 5ustar rootrootSABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/0000755000000000000000000000000013224674740021461 5ustar rootrootSABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/src/0000755000000000000000000000000013224674740022250 5ustar rootrootSABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/src/PlotKit.js0000644000000000000000000001102612701006716024163 0ustar rootroot/*** PlotKit Autoload Javascript Module. This file was adapted from MochiKit. See for documentation, downloads, license, etc. (c) 2005 Bob Ippolito. All rights Reserved. Modified by Alastair Tse, 2006, for PlotKit. ***/ if (typeof(PlotKit) == 'undefined') { PlotKit = {}; } if (typeof(PlotKit.PlotKit) == 'undefined') { PlotKit.PlotKit = {}; } PlotKit.PlotKit.NAME = "PlotKit.PlotKit"; PlotKit.PlotKit.VERSION = "0.9.1"; PlotKit.PlotKit.__repr__ = function () { return "[" + this.NAME + " " + this.VERSION + "]"; }; PlotKit.PlotKit.toString = function () { return this.__repr__(); }; PlotKit.PlotKit.SUBMODULES = [ "Base", "Layout", "Canvas", "SVG", "SweetCanvas", "SweetSVG", "EasyPlot" ]; if (typeof(JSAN) != 'undefined' || typeof(dojo) != 'undefined') { if (typeof(dojo) != 'undefined') { dojo.provide('PlotKit.PlotKit'); dojo.require("PlotKit.*"); } if (typeof(JSAN) != 'undefined') { // hopefully this makes it easier for static analysis? JSAN.use("PlotKit.Base", []); JSAN.use("PlotKit.Layout", []); JSAN.use("PlotKit.Canvas", []); JSAN.use("PlotKit.SweetCanvas", []); JSAN.use("PlotKit.SVG", []); JSAN.use("PlotKit.SweetSVG", []); } (function () { var extend = MochiKit.Base.extend; var self = PlotKit.PlotKit; var modules = self.SUBMODULES; var EXPORT = []; var EXPORT_OK = []; var EXPORT_TAGS = {}; var i, k, m, all; for (i = 0; i < modules.length; i++) { m = PlotKit[modules[i]]; extend(EXPORT, m.EXPORT); extend(EXPORT_OK, m.EXPORT_OK); for (k in m.EXPORT_TAGS) { EXPORT_TAGS[k] = extend(EXPORT_TAGS[k], m.EXPORT_TAGS[k]); } all = m.EXPORT_TAGS[":all"]; if (!all) { all = extend(null, m.EXPORT, m.EXPORT_OK); } var j; for (j = 0; j < all.length; j++) { k = all[j]; self[k] = m[k]; } } self.EXPORT = EXPORT; self.EXPORT_OK = EXPORT_OK; self.EXPORT_TAGS = EXPORT_TAGS; }()); } else { if (typeof(PlotKit.__compat__) == 'undefined') { PlotKit.__compat__ = true; } (function () { if (typeof(document) == "undefined") { return; } var scripts = document.getElementsByTagName("script"); var kXULNSURI = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var base = null; var baseElem = null; var allScripts = {}; var i; for (i = 0; i < scripts.length; i++) { var src = scripts[i].getAttribute("src"); if (!src) { continue; } allScripts[src] = true; if (src.match(/PlotKit.js$/)) { base = src.substring(0, src.lastIndexOf('PlotKit.js')); baseElem = scripts[i]; } } if (base === null) { return; } var modules = PlotKit.PlotKit.SUBMODULES; for (var i = 0; i < modules.length; i++) { if (PlotKit[modules[i]]) { continue; } var uri = base + modules[i] + '.js'; if (uri in allScripts) { continue; } if (document.documentElement && document.documentElement.namespaceURI == kXULNSURI) { // XUL var s = document.createElementNS(kXULNSURI, 'script'); s.setAttribute("id", "PlotKit_" + base + modules[i]); s.setAttribute("src", uri); s.setAttribute("type", "application/x-javascript"); baseElem.parentNode.appendChild(s); } else { // HTML /* DOM can not be used here because Safari does deferred loading of scripts unless they are in the document or inserted with document.write This is not XHTML compliant. If you want XHTML compliance then you must use the packed version of MochiKit or include each script individually (basically unroll these document.write calls into your XHTML source) */ document.write(''); } }; })(); } SABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/src/SweetSVG.js0000644000000000000000000002013512701006716024245 0ustar rootroot/* PlotKit Sweet SVG Renderer ========================== SVG Renderer for PlotKit which looks pretty! Copyright --------- Copyright 2005,2006 (c) Alastair Tse For use under the BSD license. */ // ------------------------------------------------------------------------- // Check required components // ------------------------------------------------------------------------- try { if (typeof(PlotKit.SVGRenderer) == 'undefined') { throw ""; } } catch (e) { throw "SweetSVG depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.{Layout, SVG}" } if (typeof(PlotKit.SweetSVGRenderer) == 'undefined') { PlotKit.SweetSVGRenderer = {}; } PlotKit.SweetSVGRenderer = function(element, layout, options) { if (arguments.length > 0) { this.__init__(element, layout, options); } }; PlotKit.SweetSVGRenderer.NAME = "PlotKit.SweetSVGRenderer"; PlotKit.SweetSVGRenderer.VERSION = PlotKit.VERSION; PlotKit.SweetSVGRenderer.__repr__ = function() { return "[" + this.NAME + " " + this.VERSION + "]"; }; PlotKit.SweetSVGRenderer.toString = function() { return this.__repr__(); }; // --------------------------------------------------------------------- // Subclassing Magic // --------------------------------------------------------------------- PlotKit.SweetSVGRenderer.prototype = new PlotKit.SVGRenderer(); PlotKit.SweetSVGRenderer.prototype.constructor = PlotKit.SweetSVGRenderer; PlotKit.SweetSVGRenderer.__super__ = PlotKit.SVGRenderer.prototype; // --------------------------------------------------------------------- // Constructor // --------------------------------------------------------------------- PlotKit.SweetSVGRenderer.prototype.__init__ = function(element, layout, options) { var moreOpts = PlotKit.Base.officeBlue(); MochiKit.Base.update(moreOpts, options); PlotKit.SweetSVGRenderer.__super__.__init__.call(this, element, layout, moreOpts); //this._addDropShadowFilter(); }; PlotKit.SweetSVGRenderer.prototype._addDropShadowFilter = function() { var filter = this.createSVGElement("filter", {x: 0, y: 0, "id":"dropShadow"}); var goffset = this.createSVGElement("feOffset", {"in": "SourceGraphic", "dx": 0, "dy": 0, "result": "topCopy"}); var blur = this.createSVGElement("feGaussianBlur", {"in": "SourceAlpha", "StdDeviation": 2, "result": "shadow"}); var soffset = this.createSVGElement("feOffset", {"in": "shadow", "dx": -1, "dy": -2, "result":"movedShadow"}); var merge = this.createSVGElement("feMerge"); var gmerge = this.createSVGElement("feMergeNode", {"in":"topCopy"}); var smerge = this.createSVGElement("feMergeNode", {"in":"movedShadow"}); merge.appendChild(gmerge); merge.appendChild(smerge); filter.appendChild(goffset); filter.appendChild(blur); filter.appendChild(soffset); filter.appendChild(merge); this.defs.appendChild(filter); }; // --------------------------------------------------------------------- // Extended Plotting Functions // --------------------------------------------------------------------- PlotKit.SweetSVGRenderer.prototype._renderBarChart = function() { var bind = MochiKit.Base.bind; var shadowColor = Color.blackColor().toRGBString(); var shadowStyle = "fill:" + shadowColor + ";fill-opacity:0.15"; var strokeStyle = "stroke-width: 2.0; stroke:" + Color.whiteColor().toRGBString(); var drawRect = function(attrs, bar) { var x = this.area.w * bar.x + this.area.x; var y = this.area.h * bar.y + this.area.y; var w = this.area.w * bar.w; var h = this.area.h * bar.h; if ((w < 1) || (h < 1)) return; //attrs["filter"] = "url(#dropShadow)"; attrs["style"] = strokeStyle; this._drawRect(x - 2, y - 1, w+4, h+2, {"style":shadowStyle}); this._drawRect(x, y, w, h, attrs); }; this._renderBarOrLine(this.layout.bars, bind(drawRect, this)); }; PlotKit.SweetSVGRenderer.prototype._renderLineChart = function() { var bind = MochiKit.Base.bind; var shadowColor = Color.blackColor().toRGBString(); var shadowStyle = "fill:" + shadowColor + ";fill-opacity:0.15"; var strokeStyle = "stroke-width: 2.0; stroke:" + Color.whiteColor().toRGBString(); var addPoint = function(attrs, point) { this._tempPointsBuffer += (this.area.w * point.x + this.area.x) + "," + (this.area.h * point.y + this.area.y) + " "; }; var startLine = function(attrs) { this._tempPointsBuffer = ""; this._tempPointsBuffer += (this.area.x) + "," + (this.area.y+this.area.h) + " "; }; var endLine = function(attrs) { this._tempPointsBuffer += (this.area.w + this.area.x) + "," +(this.area.h + this.area.y); attrs["points"] = this._tempPointsBuffer; attrs["stroke"] = "none"; attrs["transform"] = "translate(-2, -1)"; attrs["style"] = shadowStyle; var shadow = this.createSVGElement("polygon", attrs); this.root.appendChild(shadow); attrs["transform"] = ""; attrs["style"] = strokeStyle; var elem = this.createSVGElement("polygon", attrs); this.root.appendChild(elem); }; this._renderBarOrLine(this.layout.points, bind(addPoint, this), bind(startLine, this), bind(endLine, this)); }; PlotKit.SweetSVGRenderer.prototype._renderPieChart = function() { var centerx = this.area.x + this.area.w * 0.5; var centery = this.area.y + this.area.h * 0.5; var shadowColor = Color.blackColor().toRGBString(); var radius = Math.min(this.area.w * this.options.pieRadius, this.area.h * this.options.pieRadius); var shadowStyle = "fill:" + shadowColor + ";fill-opacity:0.15"; var shadow = this.createSVGElement("circle", {"style": shadowStyle, "cx": centerx + 1, "cy": centery + 1, "r": radius + 1}); this.root.appendChild(shadow); PlotKit.SweetSVGRenderer.__super__._renderPieChart.call(this); }; PlotKit.SweetSVGRenderer.prototype._renderBackground = function() { var attrs = { "fill": this.options.backgroundColor.toRGBString(), "stroke": "none" }; if (this.layout.style == "bar" || this.layout.style == "line") { this._drawRect(this.area.x, this.area.y, this.area.w, this.area.h, attrs); var ticks = this.layout.yticks; var horiz = false; if (this.layout.style == "bar" && this.layout.options.barOrientation == "horizontal") { ticks = this.layout.xticks; horiz = true; } for (var i = 0; i < ticks.length; i++) { var x = 0; var y = 0; var w = 0; var h = 0; if (horiz) { x = ticks[i][0] * this.area.w + this.area.x; y = this.area.y; w = 1; h = this.area.w; } else { x = this.area.x; y = ticks[i][0] * this.area.h + this.area.y; w = this.area.w; h = 1; } this._drawRect(x, y, w, h, {"fill": this.options.axisLineColor.toRGBString()}); } } else { PlotKit.SweetSVGRenderer.__super__._renderBackground.call(this); } }; // Namespace Iniitialisation PlotKit.SweetSVG = {} PlotKit.SweetSVG.SweetSVGRenderer = PlotKit.SweetSVGRenderer; PlotKit.SweetSVG.EXPORT = [ "SweetSVGRenderer" ]; PlotKit.SweetSVG.EXPORT_OK = [ "SweetSVGRenderer" ]; PlotKit.SweetSVG.__new__ = function() { var m = MochiKit.Base; m.nameFunctions(this); this.EXPORT_TAGS = { ":common": this.EXPORT, ":all": m.concat(this.EXPORT, this.EXPORT_OK) }; }; PlotKit.SweetSVG.__new__(); MochiKit.Base._exportSymbols(this, PlotKit.SweetSVG); SABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/src/Base.js0000644000000000000000000002575212701006716023462 0ustar rootroot/* PlotKit ======= PlotKit is a collection of Javascript classes that allows you to quickly visualise data using different types of charts. For license/info/documentation: http://www.liquidx.net/plotkit/ Copyright --------- Copyright 2005,2006 (c) Alastair Tse For use under the BSD license. */ // -------------------------------------------------------------------- // Check required components // -------------------------------------------------------------------- try { if (typeof(MochiKit.Base) == 'undefined' || typeof(MochiKit.DOM) == 'undefined' || typeof(MochiKit.Color) == 'undefined' || typeof(MochiKit.Format) == 'undefined') { throw ""; } } catch (e) { throw "PlotKit depends on MochiKit.{Base,Color,DOM,Format}" } // ------------------------------------------------------------------- // Inject Common Shortcuts we use into MochiKit.Color.Color // ------------------------------------------------------------------- MochiKit.Base.update(MochiKit.Color.Color.prototype, { asFillColor: function() { return this.lighterColorWithLevel(0.3); }, asStrokeColor: function() { return this.darkerColorWithLevel(0.1); }, asPointColor: function() { return this.lighterColorWithLevel(0.1); } }); // ------------------------------------------------------------------- // Define our own PlotKit namespace // ------------------------------------------------------------------- if (typeof(PlotKit) == 'undefined') { PlotKit = {}; } PlotKit.NAME = "PlotKit"; PlotKit.VERSION = "0.8"; PlotKit.__repr__ = function() { return "[" + this.NAME + " " + this.VERSION + "]"; }; PlotKit.toString = function() { return this.__repr__(); } // ------------------------------------------------------------------- // Encapsulate all our utility function into it's own namespace. // ------------------------------------------------------------------- if (typeof(PlotKit.Base) == 'undefined') { PlotKit.Base = {}; } PlotKit.Base.NAME = 'PlotKit.Base'; PlotKit.Base.VERSION = PlotKit.VERSION; PlotKit.Base.__repr__ = function() { return "[" + this.NAME + " " + this.VERSION + "]"; }; PlotKit.Base.toString = function() { return this.__repr__(); } // Detect whether we are using prototype.js PlotKit.Base.usingPrototype = function() { try { return (typeof(Object.extend) == 'function'); } catch (e) { return false; } } MochiKit.Base.update(PlotKit.Base, { roundInterval: function(range, intervals, precision) { // We want to make the interval look regular, var trunc = MochiKit.Format.roundToFixed; var sep = range/intervals; return parseFloat(trunc(sep, precision)); }, collapse: function(lst) { var m = MochiKit.Base; var biggerList = new Array(); for (var i = 0; i < lst.length; i++) { biggerList = m.concat(biggerList, lst[i]); } if (PlotKit.Base.usingPrototype()) { delete biggerList.extend; delete biggerList.from; delete biggerList.inspect; } return biggerList; }, uniq: function(sortedList) { // get unique elements in list, exactly the same as unix shell's uniq. var m = MochiKit.Base; if (!m.isArrayLike(sortedList) || (sortedList.length < 1)) return new Array(); var uniq = new Array(); var lastElem = sortedList[0]; uniq.push(sortedList[0]); for (var i = 1; i < sortedList.length; i++) { if (m.compare(sortedList[i], lastElem) != 0) { lastElem = sortedList[i]; uniq.push(sortedList[i]); } } return uniq; }, colorScheme: function() { var mb = MochiKit.Base; var mc = MochiKit.Color var scheme = ["red", "orange", "yellow", "green", "cyan", "blue", "purple", "magenta"]; var makeColor = function(name) { return mc.Color[name + "Color"]() }; return mb.map(makeColor, scheme); }, baseDarkPrimaryColors: function () { var hexColor = MochiKit.Color.Color.fromHexString; return [hexColor("#ad3f40"), hexColor("#ddac2c"), hexColor("#dfdd0c"), hexColor("#5276c4"), hexColor("#739c5a")]; }, basePrimaryColors: function () { var hexColor = MochiKit.Color.Color.fromHexString; return [hexColor("#d24c4d"), hexColor("#f2b32f"), hexColor("#ece90e"), hexColor("#5d83da"), hexColor("#78a15d")]; }, baseBlueColors: function () { var hexColor = MochiKit.Color.Color.fromHexString; return [hexColor("#4b6b94"), hexColor("#5d81b4"), hexColor("#acbad2")]; }, palette: function(baseColor, fromLevel, toLevel, increment) { var isNil = MochiKit.Base.isUndefinedOrNull; var fractions = new Array(); if (isNil(increment)) increment = 0.1; if (isNil(toLevel)) toLevel = 0.4; if (isNil(fromLevel)) fromLevel = -0.2; var level = fromLevel; while (level <= toLevel) { fractions.push(level); level += increment; } var makeColor = function(color, fraction) { return color.lighterColorWithLevel(fraction); }; return MochiKit.Base.map(partial(makeColor, baseColor), fractions); }, excanvasSupported: function() { if (/MSIE/.test(navigator.userAgent) && !window.opera) { return true; } return false; }, // The following functions are from quirksmode.org // http://www.quirksmode.org/js/findpos.html findPosX: function(obj) { var curleft = 0; if (obj.offsetParent) { while (obj.offsetParent) { curleft += obj.offsetLeft obj = obj.offsetParent; } } else if (obj.x) curleft += obj.x; return curleft; }, findPosY: function(obj) { var curtop = 0; if (obj.offsetParent) { while (obj.offsetParent) { curtop += obj.offsetTop obj = obj.offsetParent; } } else if (obj.y) curtop += obj.y; return curtop; }, isFuncLike: function(obj) { return (typeof(obj) == 'function'); } }); // // Prototype.js aware (crippled) versions of map and items. // PlotKit.Base.map = function(fn, lst) { if (PlotKit.Base.usingPrototype()) { var rval = []; for (var x in lst) { if (typeof(lst[x]) == 'function') continue; rval.push(fn(lst[x])); } return rval; } else { return MochiKit.Base.map(fn, lst); } }; PlotKit.Base.items = function(lst) { if (PlotKit.Base.usingPrototype()) { var rval = []; for (var x in lst) { if (typeof(lst[x]) == 'function') continue; rval.push([x, lst[x]]); } return rval; } else { return MochiKit.Base.items(lst); } }; PlotKit.Base.keys = function(lst) { if (PlotKit.Base.usingPrototype()) { var rval = []; for (var x in lst) { if (typeof(lst[x]) == 'function') continue; rval.push(x); } return rval; } else { return MochiKit.Base.keys(lst); } }; // // colour schemes // PlotKit.Base.baseColors = function () { var hexColor = MochiKit.Color.Color.fromHexString; return [hexColor("#476fb2"), hexColor("#be2c2b"), hexColor("#85b730"), hexColor("#734a99"), hexColor("#26a1c5"), hexColor("#fb8707"), hexColor("#000000")]; }; PlotKit.Base.officeBaseStyle = { "axisLineWidth": 2.0, "axisLabelColor": Color.grayColor(), "axisLineColor": Color.whiteColor(), "padding": {top: 5, bottom: 10, left: 30, right: 30} }; MochiKit.Base.update(PlotKit.Base,{ officeBlue: function() { var r = { "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[0]), "backgroundColor": PlotKit.Base.baseColors()[0].lighterColorWithLevel(0.45) }; MochiKit.Base.update(r, PlotKit.Base.officeBaseStyle); return r; }, officeRed: function() { var r = { "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[1]), "backgroundColor": PlotKit.Base.baseColors()[1].lighterColorWithLevel(0.5) }; MochiKit.Base.update(r, PlotKit.Base.officeBaseStyle); return r; }, officeGreen: function() { var r = { "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[2]), "backgroundColor": PlotKit.Base.baseColors()[2].lighterColorWithLevel(0.5) }; MochiKit.Base.update(r, PlotKit.Base.officeBaseStyle); return r; }, officePurple: function() { var r = { "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[3]), "backgroundColor": PlotKit.Base.baseColors()[3].lighterColorWithLevel(0.5) }; MochiKit.Base.update(r, PlotKit.Base.officeBaseStyle); return r; }, officeCyan: function() { var r = { "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[4]), "backgroundColor": PlotKit.Base.baseColors()[4].lighterColorWithLevel(0.5) }; MochiKit.Base.update(r, PlotKit.Base.officeBaseStyle); return r; }, officeOrange: function() { var r = { "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[5]), "backgroundColor": PlotKit.Base.baseColors()[5].lighterColorWithLevel(0.4) }; MochiKit.Base.update(r, PlotKit.Base.officeBaseStyle); return r; }, officeBlack: function() { var r = { "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[6], 0.0, 0.6), "backgroundColor": PlotKit.Base.baseColors()[6].lighterColorWithLevel(0.9) }; MochiKit.Base.update(r, PlotKit.Base.officeBaseStyle); return r; } }); PlotKit.Base.EXPORT = [ "baseColors", "collapse", "colorScheme", "findPosX", "findPosY", "officeBaseStyle", "officeBlue", "officeRed", "officeGreen", "officePurple", "officeCyan", "officeOrange", "officeBlack", "roundInterval", "uniq", "isFuncLike", "excanvasSupported" ]; PlotKit.Base.EXPORT_OK = []; PlotKit.Base.__new__ = function() { var m = MochiKit.Base; m.nameFunctions(this); this.EXPORT_TAGS = { ":common": this.EXPORT, ":all": m.concat(this.EXPORT, this.EXPORT_OK) }; }; PlotKit.Base.__new__(); MochiKit.Base._exportSymbols(this, PlotKit.Base); SABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/src/Canvas.js0000644000000000000000000005465712701006716024031 0ustar rootroot/* PlotKit Canvas ============== Provides HTML Canvas Renderer. This is supported under: - Safari 2.0 - Mozilla Firefox 1.5 - Opera 9.0 preview 2 - IE 6 (via VML Emulation) It uses DIVs for labels. Copyright --------- Copyright 2005,2006 (c) Alastair Tse For use under the BSD license. */ // -------------------------------------------------------------------- // Check required components // -------------------------------------------------------------------- try { if ((typeof(PlotKit.Base) == 'undefined') || (typeof(PlotKit.Layout) == 'undefined')) { throw ""; } } catch (e) { throw "PlotKit.Layout depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.{Base,Layout}" } // ------------------------------------------------------------------------ // Defines the renderer class // ------------------------------------------------------------------------ if (typeof(PlotKit.CanvasRenderer) == 'undefined') { PlotKit.CanvasRenderer = {}; } PlotKit.CanvasRenderer.NAME = "PlotKit.CanvasRenderer"; PlotKit.CanvasRenderer.VERSION = PlotKit.VERSION; PlotKit.CanvasRenderer.__repr__ = function() { return "[" + this.NAME + " " + this.VERSION + "]"; }; PlotKit.CanvasRenderer.toString = function() { return this.__repr__(); } PlotKit.CanvasRenderer = function(element, layout, options) { if (arguments.length > 0) this.__init__(element, layout, options); }; PlotKit.CanvasRenderer.prototype.__init__ = function(element, layout, options) { var isNil = MochiKit.Base.isUndefinedOrNull; var Color = MochiKit.Color.Color; // default options this.options = { "drawBackground": true, "backgroundColor": Color.whiteColor(), "padding": {left: 30, right: 30, top: 5, bottom: 10}, "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[0]), "strokeColor": Color.whiteColor(), "strokeColorTransform": "asStrokeColor", "strokeWidth": 0.5, "shouldFill": true, "shouldStroke": true, "drawXAxis": true, "drawYAxis": true, "axisLineColor": Color.blackColor(), "axisLineWidth": 0.5, "axisTickSize": 3, "axisLabelColor": Color.blackColor(), "axisLabelFont": "Arial", "axisLabelFontSize": 9, "axisLabelWidth": 50, "pieRadius": 0.4, "enableEvents": true }; MochiKit.Base.update(this.options, options ? options : {}); this.layout = layout; this.element = MochiKit.DOM.getElement(element); this.container = this.element.parentNode; // Stuff relating to Canvas on IE support this.isIE = PlotKit.Base.excanvasSupported(); if (this.isIE && !isNil(G_vmlCanvasManager)) { this.IEDelay = 0.5; this.maxTries = 5; this.renderDelay = null; this.clearDelay = null; this.element = G_vmlCanvasManager.initElement(this.element); } this.height = this.element.height; this.width = this.element.width; // --- check whether everything is ok before we return if (isNil(this.element)) throw "CanvasRenderer() - passed canvas is not found"; if (!this.isIE && !(PlotKit.CanvasRenderer.isSupported(this.element))) throw "CanvasRenderer() - Canvas is not supported."; if (isNil(this.container) || (this.container.nodeName.toLowerCase() != "div")) throw "CanvasRenderer() - needs to be enclosed in
"; // internal state this.xlabels = new Array(); this.ylabels = new Array(); this.isFirstRender = true; this.area = { x: this.options.padding.left, y: this.options.padding.top, w: this.width - this.options.padding.left - this.options.padding.right, h: this.height - this.options.padding.top - this.options.padding.bottom }; MochiKit.DOM.updateNodeAttributes(this.container, {"style":{ "position": "relative", "width": this.width + "px"}}); // load event system if we have Signals /* Disabled until we have a proper implementation try { this.event_isinside = null; if (MochiKit.Signal && this.options.enableEvents) { this._initialiseEvents(); } } catch (e) { // still experimental } */ }; PlotKit.CanvasRenderer.prototype.render = function() { if (this.isIE) { // VML takes a while to start up, so we just poll every this.IEDelay try { if (this.renderDelay) { this.renderDelay.cancel(); this.renderDelay = null; } var context = this.element.getContext("2d"); } catch (e) { this.isFirstRender = false; if (this.maxTries-- > 0) { this.renderDelay = MochiKit.Async.wait(this.IEDelay); this.renderDelay.addCallback(bind(this.render, this)); } return; } } if (this.options.drawBackground) this._renderBackground(); if (this.layout.style == "bar") { this._renderBarChart(); this._renderBarAxis(); } else if (this.layout.style == "pie") { this._renderPieChart(); this._renderPieAxis(); } else if (this.layout.style == "line") { this._renderLineChart(); this._renderLineAxis(); } }; PlotKit.CanvasRenderer.prototype._renderBarChartWrap = function(data, plotFunc) { var context = this.element.getContext("2d"); var colorCount = this.options.colorScheme.length; var colorScheme = this.options.colorScheme; var setNames = MochiKit.Base.keys(this.layout.datasets); var setCount = setNames.length; for (var i = 0; i < setCount; i++) { var setName = setNames[i]; var color = colorScheme[i%colorCount]; context.save(); context.fillStyle = color.toRGBString(); if (this.options.strokeColor) context.strokeStyle = this.options.strokeColor.toRGBString(); else if (this.options.strokeColorTransform) context.strokeStyle = color[this.options.strokeColorTransform]().toRGBString(); context.lineWidth = this.options.strokeWidth; var forEachFunc = function(obj) { if (obj.name == setName) plotFunc(context, obj); }; MochiKit.Iter.forEach(data, bind(forEachFunc, this)); context.restore(); } }; PlotKit.CanvasRenderer.prototype._renderBarChart = function() { var bind = MochiKit.Base.bind; var drawRect = function(context, bar) { var x = this.area.w * bar.x + this.area.x; var y = this.area.h * bar.y + this.area.y; var w = this.area.w * bar.w; var h = this.area.h * bar.h; if ((w < 1) || (h < 1)) return; if (this.options.shouldFill) context.fillRect(x, y, w, h); if (this.options.shouldStroke) context.strokeRect(x, y, w, h); }; this._renderBarChartWrap(this.layout.bars, bind(drawRect, this)); }; PlotKit.CanvasRenderer.prototype._renderLineChart = function() { var context = this.element.getContext("2d"); var colorCount = this.options.colorScheme.length; var colorScheme = this.options.colorScheme; var setNames = MochiKit.Base.keys(this.layout.datasets); var setCount = setNames.length; var bind = MochiKit.Base.bind; var partial = MochiKit.Base.partial; for (var i = 0; i < setCount; i++) { var setName = setNames[i]; var color = colorScheme[i%colorCount]; var strokeX = this.options.strokeColorTransform; // setup graphics context context.save(); context.fillStyle = color.toRGBString(); if (this.options.strokeColor) context.strokeStyle = this.options.strokeColor.toRGBString(); else if (this.options.strokeColorTransform) context.strokeStyle = color[strokeX]().toRGBString(); context.lineWidth = this.options.strokeWidth; // create paths var makePath = function(ctx) { ctx.beginPath(); ctx.moveTo(this.area.x, this.area.y + this.area.h); var addPoint = function(ctx_, point) { if (point.name == setName) ctx_.lineTo(this.area.w * point.x + this.area.x, this.area.h * point.y + this.area.y); }; MochiKit.Iter.forEach(this.layout.points, partial(addPoint, ctx), this); ctx.lineTo(this.area.w + this.area.x, this.area.h + this.area.y); ctx.lineTo(this.area.x, this.area.y + this.area.h); ctx.closePath(); }; if (this.options.shouldFill) { bind(makePath, this)(context); context.fill(); } if (this.options.shouldStroke) { bind(makePath, this)(context); context.stroke(); } context.restore(); } }; PlotKit.CanvasRenderer.prototype._renderPieChart = function() { var context = this.element.getContext("2d"); var colorCount = this.options.colorScheme.length; var slices = this.layout.slices; var centerx = this.area.x + this.area.w * 0.5; var centery = this.area.y + this.area.h * 0.5; var radius = Math.min(this.area.w * this.options.pieRadius, this.area.h * this.options.pieRadius); if (this.isIE) { centerx = parseInt(centerx); centery = parseInt(centery); radius = parseInt(radius); } // NOTE NOTE!! Canvas Tag draws the circle clockwise from the y = 0, x = 1 // so we have to subtract 90 degrees to make it start at y = 1, x = 0 for (var i = 0; i < slices.length; i++) { var color = this.options.colorScheme[i%colorCount]; context.save(); context.fillStyle = color.toRGBString(); var makePath = function() { context.beginPath(); context.moveTo(centerx, centery); context.arc(centerx, centery, radius, slices[i].startAngle - Math.PI/2, slices[i].endAngle - Math.PI/2, false); context.lineTo(centerx, centery); context.closePath(); }; if (Math.abs(slices[i].startAngle - slices[i].endAngle) > 0.001) { if (this.options.shouldFill) { makePath(); context.fill(); } if (this.options.shouldStroke) { makePath(); context.lineWidth = this.options.strokeWidth; if (this.options.strokeColor) context.strokeStyle = this.options.strokeColor.toRGBString(); else if (this.options.strokeColorTransform) context.strokeStyle = color[this.options.strokeColorTransform]().toRGBString(); context.stroke(); } } context.restore(); } }; PlotKit.CanvasRenderer.prototype._renderBarAxis = function() { this._renderAxis(); } PlotKit.CanvasRenderer.prototype._renderLineAxis = function() { this._renderAxis(); }; PlotKit.CanvasRenderer.prototype._renderAxis = function() { if (!this.options.drawXAxis && !this.options.drawYAxis) return; var context = this.element.getContext("2d"); var labelStyle = {"style": {"position": "absolute", "fontSize": this.options.axisLabelFontSize + "px", "zIndex": 10, "color": this.options.axisLabelColor.toRGBString(), "width": this.options.axisLabelWidth + "px", "overflow": "hidden" } }; // axis lines context.save(); context.strokeStyle = this.options.axisLineColor.toRGBString(); context.lineWidth = this.options.axisLineWidth; if (this.options.drawYAxis) { if (this.layout.yticks) { var drawTick = function(tick) { if (typeof(tick) == "function") return; var x = this.area.x; var y = this.area.y + tick[0] * this.area.h; context.beginPath(); context.moveTo(x, y); context.lineTo(x - this.options.axisTickSize, y); context.closePath(); context.stroke(); var label = DIV(labelStyle, tick[1]); label.style.top = (y - this.options.axisLabelFontSize) + "px"; label.style.left = (x - this.options.padding.left - this.options.axisTickSize) + "px"; label.style.textAlign = "right"; label.style.width = (this.options.padding.left - this.options.axisTickSize * 2) + "px"; MochiKit.DOM.appendChildNodes(this.container, label); this.ylabels.push(label); }; MochiKit.Iter.forEach(this.layout.yticks, bind(drawTick, this)); } context.beginPath(); context.moveTo(this.area.x, this.area.y); context.lineTo(this.area.x, this.area.y + this.area.h); context.closePath(); context.stroke(); } if (this.options.drawXAxis) { if (this.layout.xticks) { var drawTick = function(tick) { if (typeof(dataset) == "function") return; var x = this.area.x + tick[0] * this.area.w; var y = this.area.y + this.area.h; context.beginPath(); context.moveTo(x, y); context.lineTo(x, y + this.options.axisTickSize); context.closePath(); context.stroke(); var label = DIV(labelStyle, tick[1]); label.style.top = (y + this.options.axisTickSize) + "px"; label.style.left = (x - this.options.axisLabelWidth/2) + "px"; label.style.textAlign = "center"; label.style.width = this.options.axisLabelWidth + "px"; MochiKit.DOM.appendChildNodes(this.container, label); this.xlabels.push(label); }; MochiKit.Iter.forEach(this.layout.xticks, bind(drawTick, this)); } context.beginPath(); context.moveTo(this.area.x, this.area.y + this.area.h); context.lineTo(this.area.x + this.area.w, this.area.y + this.area.h); context.closePath(); context.stroke(); } context.restore(); }; PlotKit.CanvasRenderer.prototype._renderPieAxis = function() { if (!this.options.drawXAxis) return; if (this.layout.xticks) { // make a lookup dict for x->slice values var lookup = new Array(); for (var i = 0; i < this.layout.slices.length; i++) { lookup[this.layout.slices[i].xval] = this.layout.slices[i]; } var centerx = this.area.x + this.area.w * 0.5; var centery = this.area.y + this.area.h * 0.5; var radius = Math.min(this.area.w * this.options.pieRadius, this.area.h * this.options.pieRadius); var labelWidth = this.options.axisLabelWidth; for (var i = 0; i < this.layout.xticks.length; i++) { var slice = lookup[this.layout.xticks[i][0]]; if (MochiKit.Base.isUndefinedOrNull(slice)) continue; var angle = (slice.startAngle + slice.endAngle)/2; // normalize the angle var normalisedAngle = angle; if (normalisedAngle > Math.PI * 2) normalisedAngle = normalisedAngle - Math.PI * 2; else if (normalisedAngle < 0) normalisedAngle = normalisedAngle + Math.PI * 2; var labelx = centerx + Math.sin(normalisedAngle) * (radius + 10); var labely = centery - Math.cos(normalisedAngle) * (radius + 10); var attrib = {"position": "absolute", "zIndex": 11, "width": labelWidth + "px", "fontSize": this.options.axisLabelFontSize + "px", "overflow": "hidden", "color": this.options.axisLabelColor.toHexString() }; if (normalisedAngle <= Math.PI * 0.5) { // text on top and align left attrib["textAlign"] = "left"; attrib["verticalAlign"] = "top"; attrib["left"] = labelx + "px"; attrib["top"] = (labely - this.options.axisLabelFontSize) + "px"; } else if ((normalisedAngle > Math.PI * 0.5) && (normalisedAngle <= Math.PI)) { // text on bottom and align left attrib["textAlign"] = "left"; attrib["verticalAlign"] = "bottom"; attrib["left"] = labelx + "px"; attrib["top"] = labely + "px"; } else if ((normalisedAngle > Math.PI) && (normalisedAngle <= Math.PI*1.5)) { // text on bottom and align right attrib["textAlign"] = "right"; attrib["verticalAlign"] = "bottom"; attrib["left"] = (labelx - labelWidth) + "px"; attrib["top"] = labely + "px"; } else { // text on top and align right attrib["textAlign"] = "right"; attrib["verticalAlign"] = "bottom"; attrib["left"] = (labelx - labelWidth) + "px"; attrib["top"] = (labely - this.options.axisLabelFontSize) + "px"; } var label = DIV({'style': attrib}, this.layout.xticks[i][1]); this.xlabels.push(label); MochiKit.DOM.appendChildNodes(this.container, label); } } }; PlotKit.CanvasRenderer.prototype._renderBackground = function() { var context = this.element.getContext("2d"); context.save(); context.fillStyle = this.options.backgroundColor.toRGBString(); context.fillRect(0, 0, this.width, this.height); context.restore(); }; PlotKit.CanvasRenderer.prototype.clear = function() { if (this.isIE) { // VML takes a while to start up, so we just poll every this.IEDelay try { if (this.clearDelay) { this.clearDelay.cancel(); this.clearDelay = null; } var context = this.element.getContext("2d"); } catch (e) { this.isFirstRender = false; this.clearDelay = MochiKit.Async.wait(this.IEDelay); this.clearDelay.addCallback(bind(this.clear, this)); return; } } var context = this.element.getContext("2d"); context.clearRect(0, 0, this.width, this.height); MochiKit.Iter.forEach(this.xlabels, MochiKit.DOM.removeElement); MochiKit.Iter.forEach(this.ylabels, MochiKit.DOM.removeElement); this.xlabels = new Array(); this.ylabels = new Array(); }; // ---------------------------------------------------------------- // Everything below here is experimental and undocumented. // ---------------------------------------------------------------- PlotKit.CanvasRenderer.prototype._initialiseEvents = function() { var connect = MochiKit.Signal.connect; var bind = MochiKit.Base.bind; //MochiKit.Signal.registerSignals(this, ['onmouseover', 'onclick', 'onmouseout', 'onmousemove']); //connect(this.element, 'onmouseover', bind(this.onmouseover, this)); //connect(this.element, 'onmouseout', bind(this.onmouseout, this)); //connect(this.element, 'onmousemove', bind(this.onmousemove, this)); connect(this.element, 'onclick', bind(this.onclick, this)); }; PlotKit.CanvasRenderer.prototype._resolveObject = function(e) { // does not work in firefox //var x = (e.event().offsetX - this.area.x) / this.area.w; //var y = (e.event().offsetY - this.area.y) / this.area.h; var x = (e.mouse().page.x - PlotKit.Base.findPosX(this.element) - this.area.x) / this.area.w; var y = (e.mouse().page.y - PlotKit.Base.findPosY(this.element) - this.area.y) / this.area.h; //log(x, y); var isHit = this.layout.hitTest(x, y); if (isHit) return isHit; return null; }; PlotKit.CanvasRenderer.prototype._createEventObject = function(layoutObj, e) { if (layoutObj == null) { return null; } e.chart = layoutObj return e; }; PlotKit.CanvasRenderer.prototype.onclick = function(e) { var layoutObject = this._resolveObject(e); var eventObject = this._createEventObject(layoutObject, e); if (eventObject != null) MochiKit.Signal.signal(this, "onclick", eventObject); }; PlotKit.CanvasRenderer.prototype.onmouseover = function(e) { var layoutObject = this._resolveObject(e); var eventObject = this._createEventObject(layoutObject, e); if (eventObject != null) signal(this, "onmouseover", eventObject); }; PlotKit.CanvasRenderer.prototype.onmouseout = function(e) { var layoutObject = this._resolveObject(e); var eventObject = this._createEventObject(layoutObject, e); if (eventObject == null) signal(this, "onmouseout", e); else signal(this, "onmouseout", eventObject); }; PlotKit.CanvasRenderer.prototype.onmousemove = function(e) { var layoutObject = this._resolveObject(e); var eventObject = this._createEventObject(layoutObject, e); if ((layoutObject == null) && (this.event_isinside == null)) { // TODO: should we emit an event anyway? return; } if ((layoutObject != null) && (this.event_isinside == null)) signal(this, "onmouseover", eventObject); if ((layoutObject == null) && (this.event_isinside != null)) signal(this, "onmouseout", eventObject); if ((layoutObject != null) && (this.event_isinside != null)) signal(this, "onmousemove", eventObject); this.event_isinside = layoutObject; //log("move", x, y); }; PlotKit.CanvasRenderer.isSupported = function(canvasName) { var canvas = null; try { if (MochiKit.Base.isUndefinedOrNull(canvasName)) canvas = MochiKit.DOM.CANVAS({}); else canvas = MochiKit.DOM.getElement(canvasName); var context = canvas.getContext("2d"); } catch (e) { var ie = navigator.appVersion.match(/MSIE (\d\.\d)/); var opera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1); if ((!ie) || (ie[1] < 6) || (opera)) return false; return true; } return true; }; // Namespace Iniitialisation PlotKit.Canvas = {} PlotKit.Canvas.CanvasRenderer = PlotKit.CanvasRenderer; PlotKit.Canvas.EXPORT = [ "CanvasRenderer" ]; PlotKit.Canvas.EXPORT_OK = [ "CanvasRenderer" ]; PlotKit.Canvas.__new__ = function() { var m = MochiKit.Base; m.nameFunctions(this); this.EXPORT_TAGS = { ":common": this.EXPORT, ":all": m.concat(this.EXPORT, this.EXPORT_OK) }; }; PlotKit.Canvas.__new__(); MochiKit.Base._exportSymbols(this, PlotKit.Canvas); SABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/src/Layout.js0000644000000000000000000005726112701006716024065 0ustar rootroot/* PlotKit Layout ============== Handles laying out data on to a virtual canvas square canvas between 0.0 and 1.0. If you want to add new chart/plot types such as point plots, you need to add them here. Copyright --------- Copyright 2005,2006 (c) Alastair Tse For use under the BSD license. */ try { if (typeof(PlotKit.Base) == 'undefined') { throw "" } } catch (e) { throw "PlotKit.Layout depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.Base" } // -------------------------------------------------------------------- // Start of Layout definition // -------------------------------------------------------------------- if (typeof(PlotKit.Layout) == 'undefined') { PlotKit.Layout = {}; } PlotKit.Layout.NAME = "PlotKit.Layout"; PlotKit.Layout.VERSION = PlotKit.VERSION; PlotKit.Layout.__repr__ = function() { return "[" + this.NAME + " " + this.VERSION + "]"; }; PlotKit.Layout.toString = function() { return this.__repr__(); } PlotKit.Layout.valid_styles = ["bar", "line", "pie", "point"]; // -------------------------------------------------------------------- // Start of Layout definition // -------------------------------------------------------------------- PlotKit.Layout = function(style, options) { this.options = { "barWidthFillFraction": 0.75, "barOrientation": "vertical", "xOriginIsZero": true, "yOriginIsZero": true, "xAxis": null, // [xmin, xmax] "yAxis": null, // [ymin, ymax] "xTicks": null, // [{label: "somelabel", v: value}, ..] (label opt.) "yTicks": null, // [{label: "somelabel", v: value}, ..] (label opt.) "xNumberOfTicks": 10, "yNumberOfTicks": 5, "xTickPrecision": 1, "yTickPrecision": 1, "pieRadius": 0.4 }; // valid external options : TODO: input verification this.style = style; MochiKit.Base.update(this.options, options ? options : {}); // externally visible states // overriden if xAxis and yAxis are set in options if (!MochiKit.Base.isUndefinedOrNull(this.options.xAxis)) { this.minxval = this.options.xAxis[0]; this.maxxval = this.options.xAxis[1]; this.xscale = this.maxxval - this.minxval; } else { this.minxval = 0; this.maxxval = null; this.xscale = null; // val -> pos factor (eg, xval * xscale = xpos) } if (!MochiKit.Base.isUndefinedOrNull(this.options.yAxis)) { this.minyval = this.options.yAxis[0]; this.maxyval = this.options.yAxis[1]; this.yscale = this.maxyval - this.minyval; } else { this.minyval = 0; this.maxyval = null; this.yscale = null; } this.bars = new Array(); // array of bars to plot for bar charts this.points = new Array(); // array of points to plot for line plots this.slices = new Array(); // array of slices to draw for pie charts this.xticks = new Array(); this.yticks = new Array(); // internal states this.datasets = new Array(); this.minxdelta = 0; this.xrange = 1; this.yrange = 1; this.hitTestCache = {x2maxy: null}; }; // -------------------------------------------------------------------- // Dataset Manipulation // -------------------------------------------------------------------- PlotKit.Layout.prototype.addDataset = function(setname, set_xy) { this.datasets[setname] = set_xy; }; PlotKit.Layout.prototype.removeDataset = function(setname, set_xy) { delete this.datasets[setname]; }; PlotKit.Layout.prototype.addDatasetFromTable = function(name, tableElement, xcol, ycol, lcol) { var isNil = MochiKit.Base.isUndefinedOrNull; var scrapeText = MochiKit.DOM.scrapeText; var strip = MochiKit.Format.strip; if (isNil(xcol)) xcol = 0; if (isNil(ycol)) ycol = 1; if (isNil(lcol)) lcol = -1; var rows = tableElement.tBodies[0].rows; var data = new Array(); var labels = new Array(); if (!isNil(rows)) { for (var i = 0; i < rows.length; i++) { data.push([parseFloat(strip(scrapeText(rows[i].cells[xcol]))), parseFloat(strip(scrapeText(rows[i].cells[ycol])))]); if (lcol >= 0){ labels.push({v: parseFloat(strip(scrapeText(rows[i].cells[xcol]))), label: strip(scrapeText(rows[i].cells[lcol]))}); } } this.addDataset(name, data); if (lcol >= 0) { this.options.xTicks = labels; } return true; } return false; }; // -------------------------------------------------------------------- // Evaluates the layout for the current data and style. // -------------------------------------------------------------------- PlotKit.Layout.prototype.evaluate = function() { this._evaluateLimits(); this._evaluateScales(); if (this.style == "bar") { if (this.options.barOrientation == "horizontal") { this._evaluateHorizBarCharts(); } else { this._evaluateBarCharts(); } this._evaluateBarTicks(); } else if (this.style == "line") { this._evaluateLineCharts(); this._evaluateLineTicks(); } else if (this.style == "pie") { this._evaluatePieCharts(); this._evaluatePieTicks(); } }; // Given the fractional x, y positions, report the corresponding // x, y values. PlotKit.Layout.prototype.hitTest = function(x, y) { // TODO: make this more efficient with better datastructures // for this.bars, this.points and this.slices var f = MochiKit.Format.twoDigitFloat; if ((this.style == "bar") && this.bars && (this.bars.length > 0)) { for (var i = 0; i < this.bars.length; i++) { var bar = this.bars[i]; if ((x >= bar.x) && (x <= bar.x + bar.w) && (y >= bar.y) && (y - bar.y <= bar.h)) return bar; } } else if (this.style == "line") { if (this.hitTestCache.x2maxy == null) { this._regenerateHitTestCache(); } // 1. find the xvalues that equal or closest to the give x var xval = x / this.xscale; var xvalues = this.hitTestCache.xvalues; var xbefore = null; var xafter = null; for (var i = 1; i < xvalues.length; i++) { if (xvalues[i] > xval) { xbefore = xvalues[i-1]; xafter = xvalues[i]; break; } } if ((xbefore != null)) { var ybefore = this.hitTestCache.x2maxy[xbefore]; var yafter = this.hitTestCache.x2maxy[xafter]; var yval = (1.0 - y)/this.yscale; // interpolate whether we will fall inside or outside var gradient = (yafter - ybefore) / (xafter - xbefore); var projmaxy = ybefore + gradient * (xval - xbefore); if (projmaxy >= yval) { // inside the highest curve (roughly) var obj = {xval: xval, yval: yval, xafter: xafter, yafter: yafter, xbefore: xbefore, ybefore: ybefore, yprojected: projmaxy }; return obj; } } } else if (this.style == "pie") { var dist = Math.sqrt((y-0.5)*(y-0.5) + (x-0.5)*(x-0.5)); if (dist > this.options.pieRadius) return null; // TODO: actually doesn't work if we don't know how the Canvas // lays it out, need to fix! var angle = Math.atan2(y - 0.5, x - 0.5) - Math.PI/2; for (var i = 0; i < this.slices.length; i++) { var slice = this.slices[i]; if (slice.startAngle < angle && slice.endAngle >= angle) return slice; } } return null; }; // Reports valid position rectangle for X value (only valid for bar charts) PlotKit.Layout.prototype.rectForX = function(x) { return null; }; // Reports valid angles through which X value encloses (only valid for pie charts) PlotKit.Layout.prototype.angleRangeForX = function(x) { return null; }; // -------------------------------------------------------------------- // START Internal Functions // -------------------------------------------------------------------- PlotKit.Layout.prototype._evaluateLimits = function() { // take all values from all datasets and find max and min var map = PlotKit.Base.map; var items = PlotKit.Base.items; var itemgetter = MochiKit.Base.itemgetter; var collapse = PlotKit.Base.collapse; var listMin = MochiKit.Base.listMin; var listMax = MochiKit.Base.listMax; var isNil = MochiKit.Base.isUndefinedOrNull; var all = collapse(map(itemgetter(1), items(this.datasets))); if (isNil(this.options.xAxis)) { if (this.options.xOriginIsZero) this.minxval = 0; else this.minxval = listMin(map(parseFloat, map(itemgetter(0), all))); this.maxxval = listMax(map(parseFloat, map(itemgetter(0), all))); } else { this.minxval = this.options.xAxis[0]; this.maxxval = this.options.xAxis[1]; this.xscale = this.maxval - this.minxval; } if (isNil(this.options.yAxis)) { if (this.options.yOriginIsZero) this.minyval = 0; else this.minyval = listMin(map(parseFloat, map(itemgetter(1), all))); this.maxyval = listMax(map(parseFloat, map(itemgetter(1), all))); } else { this.minyval = this.options.yAxis[0]; this.maxyval = this.options.yAxis[1]; this.yscale = this.maxyval - this.minyval; } }; PlotKit.Layout.prototype._evaluateScales = function() { var isNil = MochiKit.Base.isUndefinedOrNull; this.xrange = this.maxxval - this.minxval; if (this.xrange == 0) this.xscale = 1.0; else this.xscale = 1/this.xrange; this.yrange = this.maxyval - this.minyval; if (this.yrange == 0) this.yscale = 1.0; else this.yscale = 1/this.yrange; }; PlotKit.Layout.prototype._uniqueXValues = function() { var collapse = PlotKit.Base.collapse; var map = PlotKit.Base.map; var uniq = PlotKit.Base.uniq; var getter = MochiKit.Base.itemgetter; var items = PlotKit.Base.items; var xvalues = map(parseFloat, map(getter(0), collapse(map(getter(1), items(this.datasets))))); xvalues.sort(MochiKit.Base.compare); return uniq(xvalues); }; // Create the bars PlotKit.Layout.prototype._evaluateBarCharts = function() { var items = PlotKit.Base.items; var setCount = items(this.datasets).length; // work out how far separated values are var xdelta = 10000000; var xvalues = this._uniqueXValues(); for (var i = 1; i < xvalues.length; i++) { xdelta = Math.min(Math.abs(xvalues[i] - xvalues[i-1]), xdelta); } var barWidth = 0; var barWidthForSet = 0; var barMargin = 0; if (xvalues.length == 1) { // note we have to do something smarter if we only plot one value xdelta = 1.0; this.xscale = 1.0; this.minxval = xvalues[0]; barWidth = 1.0 * this.options.barWidthFillFraction; barWidthForSet = barWidth/setCount; barMargin = (1.0 - this.options.barWidthFillFraction)/2; } else { // readjust xscale to fix with bar charts if (this.xrange == 1) { this.xscale = 0.5; } else if (this.xrange == 2) { this.xscale = 1/3.0; } else { this.xscale = (1.0 - xdelta/this.xrange)/this.xrange; } barWidth = xdelta * this.xscale * this.options.barWidthFillFraction; barWidthForSet = barWidth / setCount; barMargin = xdelta * this.xscale * (1.0 - this.options.barWidthFillFraction)/2; } this.minxdelta = xdelta; // need this for tick positions // add all the rects this.bars = new Array(); var i = 0; for (var setName in this.datasets) { var dataset = this.datasets[setName]; if (PlotKit.Base.isFuncLike(dataset)) continue; for (var j = 0; j < dataset.length; j++) { var item = dataset[j]; var rect = { x: ((parseFloat(item[0]) - this.minxval) * this.xscale) + (i * barWidthForSet) + barMargin, y: 1.0 - ((parseFloat(item[1]) - this.minyval) * this.yscale), w: barWidthForSet, h: ((parseFloat(item[1]) - this.minyval) * this.yscale), xval: parseFloat(item[0]), yval: parseFloat(item[1]), name: setName }; if ((rect.x >= 0.0) && (rect.x <= 1.0) && (rect.y >= 0.0) && (rect.y <= 1.0)) { this.bars.push(rect); } } i++; } }; // Create the horizontal bars PlotKit.Layout.prototype._evaluateHorizBarCharts = function() { var items = PlotKit.Base.items; var setCount = items(this.datasets).length; // work out how far separated values are var xdelta = 10000000; var xvalues = this._uniqueXValues(); for (var i = 1; i < xvalues.length; i++) { xdelta = Math.min(Math.abs(xvalues[i] - xvalues[i-1]), xdelta); } var barWidth = 0; var barWidthForSet = 0; var barMargin = 0; // work out how far each far each bar is separated if (xvalues.length == 1) { // do something smarter if we only plot one value xdelta = 1.0; this.xscale = 1.0; this.minxval = xvalues[0]; barWidth = 1.0 * this.options.barWidthFillFraction; barWidthForSet = barWidth/setCount; barMargin = (1.0 - this.options.barWidthFillFraction)/2; } else { // readjust yscale to fix with bar charts this.xscale = (1.0 - xdelta/this.xrange)/this.xrange; barWidth = xdelta * this.xscale * this.options.barWidthFillFraction; barWidthForSet = barWidth / setCount; barMargin = xdelta * this.xscale * (1.0 - this.options.barWidthFillFraction)/2; } this.minxdelta = xdelta; // need this for tick positions // add all the rects this.bars = new Array(); var i = 0; for (var setName in this.datasets) { var dataset = this.datasets[setName]; if (PlotKit.Base.isFuncLike(dataset)) continue; for (var j = 0; j < dataset.length; j++) { var item = dataset[j]; var rect = { y: ((parseFloat(item[0]) - this.minxval) * this.xscale) + (i * barWidthForSet) + barMargin, x: 0.0, h: barWidthForSet, w: ((parseFloat(item[1]) - this.minyval) * this.yscale), xval: parseFloat(item[0]), yval: parseFloat(item[1]), name: setName }; // limit the x, y values so they do not overdraw if (rect.y <= 0.0) { rect.y = 0.0; } if (rect.y >= 1.0) { rect.y = 1.0; } if ((rect.x >= 0.0) && (rect.x <= 1.0)) { this.bars.push(rect); } } i++; } }; // Create the line charts PlotKit.Layout.prototype._evaluateLineCharts = function() { var items = PlotKit.Base.items; var setCount = items(this.datasets).length; // add all the rects this.points = new Array(); var i = 0; for (var setName in this.datasets) { var dataset = this.datasets[setName]; if (PlotKit.Base.isFuncLike(dataset)) continue; dataset.sort(function(a, b) { return compare(parseFloat(a[0]), parseFloat(b[0])); }); for (var j = 0; j < dataset.length; j++) { var item = dataset[j]; var point = { x: ((parseFloat(item[0]) - this.minxval) * this.xscale), y: 1.0 - ((parseFloat(item[1]) - this.minyval) * this.yscale), xval: parseFloat(item[0]), yval: parseFloat(item[1]), name: setName }; // limit the x, y values so they do not overdraw if (point.y <= 0.0) { point.y = 0.0; } if (point.y >= 1.0) { point.y = 1.0; } if ((point.x >= 0.0) && (point.x <= 1.0)) { this.points.push(point); } } i++; } }; // Create the pie charts PlotKit.Layout.prototype._evaluatePieCharts = function() { var items = PlotKit.Base.items; var sum = MochiKit.Iter.sum; var getter = MochiKit.Base.itemgetter; var setCount = items(this.datasets).length; // we plot the y values of the first dataset var dataset = items(this.datasets)[0][1]; var total = sum(map(getter(1), dataset)); this.slices = new Array(); var currentAngle = 0.0; for (var i = 0; i < dataset.length; i++) { var fraction = dataset[i][1] / total; var startAngle = currentAngle * Math.PI * 2; var endAngle = (currentAngle + fraction) * Math.PI * 2; var slice = {fraction: fraction, xval: dataset[i][0], yval: dataset[i][1], startAngle: startAngle, endAngle: endAngle }; if (dataset[i][1] != 0) { this.slices.push(slice); } currentAngle += fraction; } }; PlotKit.Layout.prototype._evaluateLineTicksForXAxis = function() { var isNil = MochiKit.Base.isUndefinedOrNull; if (this.options.xTicks) { // we use use specified ticks with optional labels this.xticks = new Array(); var makeTicks = function(tick) { var label = tick.label; if (isNil(label)) label = tick.v.toString(); var pos = this.xscale * (tick.v - this.minxval); if ((pos >= 0.0) && (pos <= 1.0)) { this.xticks.push([pos, label]); } }; MochiKit.Iter.forEach(this.options.xTicks, bind(makeTicks, this)); } else if (this.options.xNumberOfTicks) { // we use defined number of ticks as hint to auto generate var xvalues = this._uniqueXValues(); var roughSeparation = this.xrange / this.options.xNumberOfTicks; var tickCount = 0; this.xticks = new Array(); for (var i = 0; i <= xvalues.length; i++) { if ((xvalues[i] - this.minxval) >= (tickCount * roughSeparation)) { var pos = this.xscale * (xvalues[i] - this.minxval); if ((pos > 1.0) || (pos < 0.0)) continue; this.xticks.push([pos, xvalues[i]]); tickCount++; } if (tickCount > this.options.xNumberOfTicks) break; } } }; PlotKit.Layout.prototype._evaluateLineTicksForYAxis = function() { var isNil = MochiKit.Base.isUndefinedOrNull; if (this.options.yTicks) { this.yticks = new Array(); var makeTicks = function(tick) { var label = tick.label; if (isNil(label)) label = tick.v.toString(); var pos = 1.0 - (this.yscale * (tick.v - this.minyval)); if ((pos >= 0.0) && (pos <= 1.0)) { this.yticks.push([pos, label]); } }; MochiKit.Iter.forEach(this.options.yTicks, bind(makeTicks, this)); } else if (this.options.yNumberOfTicks) { // We use the optionally defined number of ticks as a guide this.yticks = new Array(); // if we get this separation right, we'll have good looking graphs var roundInt = PlotKit.Base.roundInterval; var prec = this.options.yTickPrecision; var roughSeparation = roundInt(this.yrange, this.options.yNumberOfTicks, prec); // round off each value of the y-axis to the precision // eg. 1.3333 at precision 1 -> 1.3 for (var i = 0; i <= this.options.yNumberOfTicks; i++) { var yval = this.minyval + (i * roughSeparation); var pos = 1.0 - ((yval - this.minyval) * this.yscale); if ((pos > 1.0) || (pos < 0.0)) continue; this.yticks.push([pos, MochiKit.Format.roundToFixed(yval, prec)]); } } }; PlotKit.Layout.prototype._evaluateLineTicks = function() { this._evaluateLineTicksForXAxis(); this._evaluateLineTicksForYAxis(); }; PlotKit.Layout.prototype._evaluateBarTicks = function() { this._evaluateLineTicks(); var centerInBar = function(tick) { return [tick[0] + (this.minxdelta * this.xscale)/2, tick[1]]; }; this.xticks = MochiKit.Base.map(bind(centerInBar, this), this.xticks); if (this.options.barOrientation == "horizontal") { // swap scales var tempticks = this.xticks; this.xticks = this.yticks; this.yticks = tempticks; // we need to invert the "yaxis" (which is now the xaxis when drawn) var invert = function(tick) { return [1.0 - tick[0], tick[1]]; } this.xticks = MochiKit.Base.map(invert, this.xticks); } }; PlotKit.Layout.prototype._evaluatePieTicks = function() { var isNil = MochiKit.Base.isUndefinedOrNull; var formatter = MochiKit.Format.numberFormatter("#%"); this.xticks = new Array(); if (this.options.xTicks) { // make a lookup dict for x->slice values var lookup = new Array(); for (var i = 0; i < this.slices.length; i++) { lookup[this.slices[i].xval] = this.slices[i]; } for (var i =0; i < this.options.xTicks.length; i++) { var tick = this.options.xTicks[i]; var slice = lookup[tick.v]; var label = tick.label; if (slice) { if (isNil(label)) label = tick.v.toString(); label += " (" + formatter(slice.fraction) + ")"; this.xticks.push([tick.v, label]); } } } else { // we make our own labels from all the slices for (var i =0; i < this.slices.length; i++) { var slice = this.slices[i]; var label = slice.xval + " (" + formatter(slice.fraction) + ")"; this.xticks.push([slice.xval, label]); } } }; PlotKit.Layout.prototype._regenerateHitTestCache = function() { this.hitTestCache.xvalues = this._uniqueXValues(); this.hitTestCache.xlookup = new Array(); this.hitTestCache.x2maxy = new Array(); var listMax = MochiKit.Base.listMax; var itemgetter = MochiKit.Base.itemgetter; var map = MochiKit.Base.map; // generate a lookup table for x values to y values var setNames = keys(this.datasets); for (var i = 0; i < setNames.length; i++) { var dataset = this.datasets[setNames[i]]; for (var j = 0; j < dataset.length; j++) { var xval = dataset[j][0]; var yval = dataset[j][1]; if (this.hitTestCache.xlookup[xval]) this.hitTestCache.xlookup[xval].push([yval, setNames[i]]); else this.hitTestCache.xlookup[xval] = [[yval, setNames[i]]]; } } for (var x in this.hitTestCache.xlookup) { var yvals = this.hitTestCache.xlookup[x]; this.hitTestCache.x2maxy[x] = listMax(map(itemgetter(0), yvals)); } }; // -------------------------------------------------------------------- // END Internal Functions // -------------------------------------------------------------------- // Namespace Iniitialisation PlotKit.LayoutModule = {}; PlotKit.LayoutModule.Layout = PlotKit.Layout; PlotKit.LayoutModule.EXPORT = [ "Layout" ]; PlotKit.LayoutModule.EXPORT_OK = []; PlotKit.LayoutModule.__new__ = function() { var m = MochiKit.Base; m.nameFunctions(this); this.EXPORT_TAGS = { ":common": this.EXPORT, ":all": m.concat(this.EXPORT, this.EXPORT_OK) }; }; PlotKit.LayoutModule.__new__(); MochiKit.Base._exportSymbols(this, PlotKit.LayoutModule); SABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/src/SVG.js0000644000000000000000000006217612701006716023250 0ustar rootroot/* PlotKit SVG =========== SVG Renderer for PlotKit Copyright --------- Copyright 2005,2006 (c) Alastair Tse For use under the BSD license. */ // ------------------------------------------------------------------------- // NOTES: - If you use XHTML1.1 strict, then you must include each MochiKit // file individuall. // - For IE support, you must include the AdobeSVG object hack. // See tests/svg.html for details. // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- // Check required components // ------------------------------------------------------------------------- try { if (typeof(PlotKit.Layout) == 'undefined') { throw ""; } } catch (e) { throw "PlotKit depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.Layout" } // --------------------------------------------------------------------------- // SVG Renderer // --------------------------------------------------------------------------- PlotKit.SVGRenderer = function(element, layout, options) { if (arguments.length > 0) this.__init__(element, layout, options); }; PlotKit.SVGRenderer.NAME = "PlotKit.SVGRenderer"; PlotKit.SVGRenderer.VERSION = PlotKit.VERSION; PlotKit.SVGRenderer.__repr__ = function() { return "[" + this.NAME + " " + this.VERSION + "]"; }; PlotKit.SVGRenderer.toString = function() { return this.__repr__(); } PlotKit.SVGRenderer.SVGNS = 'http://www.w3.org/2000/svg'; PlotKit.SVGRenderer.prototype.__init__ = function(element, layout, options) { var isNil = MochiKit.Base.isUndefinedOrNull; // default options this.options = { "drawBackground": true, "backgroundColor": Color.whiteColor(), "padding": {left: 30, right: 30, top: 5, bottom: 10}, "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[1]), "strokeColor": Color.whiteColor(), "strokeColorTransform": "asStrokeColor", "strokeWidth": 0.5, "shouldFill": true, "shouldStroke": true, "drawXAxis": true, "drawYAxis": true, "axisLineColor": Color.blackColor(), "axisLineWidth": 0.5, "axisTickSize": 3, "axisLabelColor": Color.blackColor(), "axisLabelFont": "Arial", "axisLabelFontSize": 9, "axisLabelWidth": 50, "axisLabelUseDiv": true, "pieRadius": 0.4, "enableEvents": true }; MochiKit.Base.update(this.options, options ? options : {}); this.layout = layout; this.element = MochiKit.DOM.getElement(element); this.container = this.element.parentNode; this.height = parseInt(this.element.getAttribute("height")); this.width = parseInt(this.element.getAttribute("width")); this.document = document; this.root = this.element; // Adobe SVG Support: // - if an exception is thrown, then no Adobe SVG Plugin support. try { this.document = this.element.getSVGDocument(); this.root = isNil(this.document.documentElement) ? this.element : this.document.documentElement; } catch (e) { } this.element.style.zIndex = 1; if (isNil(this.element)) throw "SVGRenderer() - passed SVG object is not found"; if (isNil(this.container) || this.container.nodeName.toLowerCase() != "div") throw "SVGRenderer() - No DIV's around the SVG."; // internal state this.xlabels = new Array(); this.ylabels = new Array(); // initialise some meta structures in SVG this.defs = this.createSVGElement("defs"); this.area = { x: this.options.padding.left, y: this.options.padding.top, w: this.width - this.options.padding.left - this.options.padding.right, h: this.height - this.options.padding.top - this.options.padding.bottom }; MochiKit.DOM.updateNodeAttributes(this.container, {"style":{ "position": "relative", "width": this.width + "px"}}); }; PlotKit.SVGRenderer.prototype.render = function() { if (this.options.drawBackground) this._renderBackground(); if (this.layout.style == "bar") { this._renderBarChart(); this._renderBarAxis(); } else if (this.layout.style == "pie") { this._renderPieChart(); this._renderPieAxis(); } else if (this.layout.style == "line") { this._renderLineChart(); this._renderLineAxis(); } }; PlotKit.SVGRenderer.prototype._renderBarOrLine = function(data, plotFunc, startFunc, endFunc) { var colorCount = this.options.colorScheme.length; var colorScheme = this.options.colorScheme; var setNames = MochiKit.Base.keys(this.layout.datasets); var setCount = setNames.length; for (var i = 0; i < setCount; i++) { var setName = setNames[i]; var attrs = new Array(); var color = colorScheme[i%colorCount]; if (this.options.shouldFill) attrs["fill"] = color.toRGBString(); else attrs["fill"] = "none"; if (this.options.shouldStroke && (this.options.strokeColor || this.options.strokeColorTransform)) { if (this.options.strokeColor) attrs["stroke"] = this.options.strokeColor.toRGBString(); else if (this.options.strokeColorTransform) attrs["stroke"] = color[this.options.strokeColorTransform]().toRGBString(); attrs["strokeWidth"] = this.options.strokeWidth; } if (startFunc) startFunc(attrs); var forEachFunc = function(obj) { if (obj.name == setName) plotFunc(attrs, obj); }; MochiKit.Iter.forEach(data, bind(forEachFunc, this)); if (endFunc) endFunc(attrs); } }; PlotKit.SVGRenderer.prototype._renderBarChart = function() { var bind = MochiKit.Base.bind; var drawRect = function(attrs, bar) { var x = this.area.w * bar.x + this.area.x; var y = this.area.h * bar.y + this.area.y; var w = this.area.w * bar.w; var h = this.area.h * bar.h; this._drawRect(x, y, w, h, attrs); }; this._renderBarOrLine(this.layout.bars, bind(drawRect, this)); }; PlotKit.SVGRenderer.prototype._renderLineChart = function() { var bind = MochiKit.Base.bind; var addPoint = function(attrs, point) { this._tempPointsBuffer += (this.area.w * point.x + this.area.x) + "," + (this.area.h * point.y + this.area.y) + " "; }; var startLine = function(attrs) { this._tempPointsBuffer = ""; this._tempPointsBuffer += (this.area.x) + "," + (this.area.y+this.area.h) + " "; }; var endLine = function(attrs) { this._tempPointsBuffer += (this.area.w + this.area.x) + "," +(this.area.h + this.area.y); attrs["points"] = this._tempPointsBuffer; var elem = this.createSVGElement("polygon", attrs); this.root.appendChild(elem); }; this._renderBarOrLine(this.layout.points, bind(addPoint, this), bind(startLine, this), bind(endLine, this)); }; PlotKit.SVGRenderer.prototype._renderPieChart = function() { var colorCount = this.options.colorScheme.length; var slices = this.layout.slices; var centerx = this.area.x + this.area.w * 0.5; var centery = this.area.y + this.area.h * 0.5; var radius = Math.min(this.area.w * this.options.pieRadius, this.area.h * this.options.pieRadius); // NOTE NOTE!! Canvas Tag draws the circle clockwise from the y = 0, x = 1 // so we have to subtract 90 degrees to make it start at y = 1, x = 0 // workaround if we only have 1 slice of 100% if (slices.length == 1 && (Math.abs(slices[0].startAngle) - Math.abs(slices[0].endAngle) < 0.1)) { var attrs = {"cx": centerx , "cy": centery , "r": radius }; var color = this.options.colorScheme[0]; if (this.options.shouldFill) attrs["fill"] = color.toRGBString(); else attrs["fill"] = "none"; if (this.options.shouldStroke && (this.options.strokeColor || this.options.strokeColorTransform)) { if (this.options.strokeColor) attrs["stroke"] = this.options.strokeColor.toRGBString(); else if (this.options.strokeColorTransform) attrs["stroke"] = color[this.options.strokeColorTransform]().toRGBString(); attrs["style"] = "stroke-width: " + this.options.strokeWidth; } this.root.appendChild(this.createSVGElement("circle", attrs)); return; } for (var i = 0; i < slices.length; i++) { var attrs = new Array(); var color = this.options.colorScheme[i%colorCount]; if (this.options.shouldFill) attrs["fill"] = color.toRGBString(); else attrs["fill"] = "none"; if (this.options.shouldStroke && (this.options.strokeColor || this.options.strokeColorTransform)) { if (this.options.strokeColor) attrs["stroke"] = this.options.strokeColor.toRGBString(); else if (this.options.strokeColorTransform) attrs["stroke"] = color[this.options.strokeColorTransform]().toRGBString(); attrs["style"] = "stroke-width:" + this.options.strokeWidth; } var largearc = 0; if (Math.abs(slices[i].endAngle - slices[i].startAngle) > Math.PI) largearc = 1; var x1 = Math.cos(slices[i].startAngle - Math.PI/2) * radius; var y1 = Math.sin(slices[i].startAngle - Math.PI/2) * radius; var x2 = Math.cos(slices[i].endAngle - Math.PI/2) * radius; var y2 = Math.sin(slices[i].endAngle - Math.PI/2) * radius; var rx = x2 - x1; var ry = y2 - y1; var pathString = "M" + centerx + "," + centery + " "; pathString += "l" + x1 + "," + y1 + " "; pathString += "a" + radius + "," + radius + " 0 " + largearc + ",1 " + rx + "," + ry + " z"; attrs["d"] = pathString; var elem = this.createSVGElement("path", attrs); this.root.appendChild(elem); } }; PlotKit.SVGRenderer.prototype._renderBarAxis = function() { this._renderAxis(); } PlotKit.SVGRenderer.prototype._renderLineAxis = function() { this._renderAxis(); }; PlotKit.SVGRenderer.prototype._renderAxis = function() { if (!this.options.drawXAxis && !this.options.drawYAxis) return; var labelStyle = {"style": {"position": "absolute", "textAlign": "center", "fontSize": this.options.axisLabelFontSize + "px", "zIndex": 10, "color": this.options.axisLabelColor.toRGBString(), "width": this.options.axisLabelWidth + "px", "overflow": "hidden" } }; // axis lines var lineAttrs = { "stroke": this.options.axisLineColor.toRGBString(), "strokeWidth": this.options.axisLineWidth }; if (this.options.drawYAxis) { if (this.layout.yticks) { var drawTick = function(tick) { var x = this.area.x; var y = this.area.y + tick[0] * this.area.h; this._drawLine(x, y, x - 3, y, lineAttrs); if (this.options.axisLabelUseDiv) { var label = DIV(labelStyle, tick[1]); label.style.top = (y - this.options.axisLabelFontSize) + "px"; label.style.left = (x - this.options.padding.left + this.options.axisTickSize) + "px"; label.style.textAlign = "left"; label.style.width = (this.options.padding.left - 3) + "px"; MochiKit.DOM.appendChildNodes(this.container, label); this.ylabels.push(label); } else { var attrs = { y: y + 3, x: (x - this.options.padding.left + 3), width: (this.options.padding.left - this.options.axisTickSize) + "px", height: (this.options.axisLabelFontSize + 3) + "px", fontFamily: "Arial", fontSize: this.options.axisLabelFontSize + "px", fill: this.options.axisLabelColor.toRGBString() }; /* we can do clipping just like DIVs http://www.xml.com/pub/a/2004/06/02/svgtype.html */ /* var mask = this.createSVGElement("mask", {id: "mask" + tick[0]}); var maskShape = this.createSVGElement("rect", {y: y + 3, x: (x - this.options.padding.left + 3), width: (this.options.padding.left - this.options.axisTickSize) + "px", height: (this.options.axisLabelFontSize + 3) + "px", style: {"fill": "#ffffff", "stroke": "#000000"}}); mask.appendChild(maskShape); this.defs.appendChild(mask); attrs["filter"] = "url(#mask" + tick[0] + ")"; */ var label = this.createSVGElement("text", attrs); label.appendChild(this.document.createTextNode(tick[1])); this.root.appendChild(label); } }; MochiKit.Iter.forEach(this.layout.yticks, bind(drawTick, this)); } this._drawLine(this.area.x, this.area.y, this.area.x, this.area.y + this.area.h, lineAttrs); } if (this.options.drawXAxis) { if (this.layout.xticks) { var drawTick = function(tick) { var x = this.area.x + tick[0] * this.area.w; var y = this.area.y + this.area.h; this._drawLine(x, y, x, y + this.options.axisTickSize, lineAttrs); if (this.options.axisLabelUseDiv) { var label = DIV(labelStyle, tick[1]); label.style.top = (y + this.options.axisTickSize) + "px"; label.style.left = (x - this.options.axisLabelWidth/2) + "px"; label.style.textAlign = "center"; label.style.width = this.options.axisLabelWidth + "px"; MochiKit.DOM.appendChildNodes(this.container, label); this.xlabels.push(label); } else { var attrs = { y: (y + this.options.axisTickSize + this.options.axisLabelFontSize), x: x - 3, width: this.options.axisLabelWidth + "px", height: (this.options.axisLabelFontSize + 3) + "px", fontFamily: "Arial", fontSize: this.options.axisLabelFontSize + "px", fill: this.options.axisLabelColor.toRGBString(), textAnchor: "middle" }; var label = this.createSVGElement("text", attrs); label.appendChild(this.document.createTextNode(tick[1])); this.root.appendChild(label); } }; MochiKit.Iter.forEach(this.layout.xticks, bind(drawTick, this)); } this._drawLine(this.area.x, this.area.y + this.area.h, this.area.x + this.area.w, this.area.y + this.area.h, lineAttrs) } }; PlotKit.SVGRenderer.prototype._renderPieAxis = function() { if (this.layout.xticks) { // make a lookup dict for x->slice values var lookup = new Array(); for (var i = 0; i < this.layout.slices.length; i++) { lookup[this.layout.slices[i].xval] = this.layout.slices[i]; } var centerx = this.area.x + this.area.w * 0.5; var centery = this.area.y + this.area.h * 0.5; var radius = Math.min(this.area.w * this.options.pieRadius + 10, this.area.h * this.options.pieRadius + 10); var labelWidth = this.options.axisLabelWidth; for (var i = 0; i < this.layout.xticks.length; i++) { var slice = lookup[this.layout.xticks[i][0]]; if (MochiKit.Base.isUndefinedOrNull(slice)) continue; var angle = (slice.startAngle + slice.endAngle)/2; // normalize the angle var normalisedAngle = angle; if (normalisedAngle > Math.PI * 2) normalisedAngle = normalisedAngle - Math.PI * 2; else if (normalisedAngle < 0) normalisedAngle = normalisedAngle + Math.PI * 2; var labelx = centerx + Math.sin(normalisedAngle) * (radius + 10); var labely = centery - Math.cos(normalisedAngle) * (radius + 10); var attrib = { "position": "absolute", "zIndex": 11, "width": labelWidth + "px", "fontSize": this.options.axisLabelFontSize + "px", "overflow": "hidden", "color": this.options.axisLabelColor.toHexString() }; var svgattrib = { "width": labelWidth + "px", "fontSize": this.options.axisLabelFontSize + "px", "height": (this.options.axisLabelFontSize + 3) + "px", "fill": this.options.axisLabelColor.toRGBString() }; if (normalisedAngle <= Math.PI * 0.5) { // text on top and align left MochiKit.Base.update(attrib, { 'textAlign': 'left', 'verticalAlign': 'top', 'left': labelx + 'px', 'top': (labely - this.options.axisLabelFontSize) + "px" }); MochiKit.Base.update(svgattrib, { "x": labelx, "y" :(labely - this.options.axisLabelFontSize), "textAnchor": "left" }); } else if ((normalisedAngle > Math.PI * 0.5) && (normalisedAngle <= Math.PI)) { // text on bottom and align left MochiKit.Base.update(attrib, { 'textAlign': 'left', 'verticalAlign': 'bottom', 'left': labelx + 'px', 'top': labely + "px" }); MochiKit.Base.update(svgattrib, { 'textAnchor': 'left', 'x': labelx, 'y': labely }); } else if ((normalisedAngle > Math.PI) && (normalisedAngle <= Math.PI*1.5)) { // text on bottom and align right MochiKit.Base.update(attrib, { 'textAlign': 'right', 'verticalAlign': 'bottom', 'left': labelx + 'px', 'top': labely + "px" }); MochiKit.Base.update(svgattrib, { 'textAnchor': 'right', 'x': labelx - labelWidth, 'y': labely }); } else { // text on top and align right MochiKit.Base.update(attrib, { 'textAlign': 'left', 'verticalAlign': 'bottom', 'left': labelx + 'px', 'top': labely + "px" }); MochiKit.Base.update(svgattrib, { 'textAnchor': 'left', 'x': labelx - labelWidth, 'y': labely - this.options.axisLabelFontSize }); } if (this.options.axisLabelUseDiv) { var label = DIV({'style': attrib}, this.layout.xticks[i][1]); this.xlabels.push(label); MochiKit.DOM.appendChildNodes(this.container, label); } else { var label = this.createSVGElement("text", svgattrib); label.appendChild(this.document.createTextNode(this.layout.xticks[i][1])) this.root.appendChild(label); } } } }; PlotKit.SVGRenderer.prototype._renderBackground = function() { var opts = {"stroke": "none", "fill": this.options.backgroundColor.toRGBString() }; this._drawRect(0, 0, this.width, this.height, opts); }; PlotKit.SVGRenderer.prototype._drawRect = function(x, y, w, h, moreattrs) { var attrs = {x: x + "px", y: y + "px", width: w + "px", height: h + "px"}; if (moreattrs) MochiKit.Base.update(attrs, moreattrs); var elem = this.createSVGElement("rect", attrs); this.root.appendChild(elem); }; PlotKit.SVGRenderer.prototype._drawLine = function(x1, y1, x2, y2, moreattrs) { var attrs = {x1: x1 + "px", y1: y1 + "px", x2: x2 + "px", y2: y2 + "px"}; if (moreattrs) MochiKit.Base.update(attrs, moreattrs); var elem = this.createSVGElement("line", attrs); this.root.appendChild(elem); } PlotKit.SVGRenderer.prototype.clear = function() { while(this.element.firstChild) { this.element.removeChild(this.element.firstChild); } if (this.options.axisLabelUseDiv) { for (var i = 0; i < this.xlabels.length; i++) { MochiKit.DOM.removeElement(this.xlabels[i]); } for (var i = 0; i < this.ylabels.length; i++) { MochiKit.DOM.removeElement(this.ylabels[i]); } } this.xlabels = new Array(); this.ylabels = new Array(); }; PlotKit.SVGRenderer.prototype.createSVGElement = function(name, attrs) { var isNil = MochiKit.Base.isUndefinedOrNull; var elem; var doc = isNil(this.document) ? document : this.document; try { elem = doc.createElementNS(PlotKit.SVGRenderer.SVGNS, name); } catch (e) { elem = doc.createElement(name); elem.setAttribute("xmlns", PlotKit.SVGRenderer.SVGNS); } if (attrs) MochiKit.DOM.updateNodeAttributes(elem, attrs); // TODO: we don't completely emulate the MochiKit.DOM.createElement // as we don't care about nodes contained. We really should though. return elem; }; PlotKit.SVGRenderer.SVG = function(attrs) { // we have to do things differently for IE+AdobeSVG. // My guess this works (via trial and error) is that we need to // have an SVG object in order to use SVGDocument.createElementNS // but IE doesn't allow us to that. var ie = navigator.appVersion.match(/MSIE (\d\.\d)/); var opera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1); if (ie && (ie[1] >= 6) && (!opera)) { var width = attrs["width"] ? attrs["width"] : "100"; var height = attrs["height"] ? attrs["height"] : "100"; var eid = attrs["id"] ? attrs["id"] : "notunique"; var html = ''; var canvas = document.createElement(html); // create embedded SVG inside SVG. var group = canvas.getSVGDocument().createElementNS(PlotKit.SVGRenderer.SVGNS, "svg"); group.setAttribute("width", width); group.setAttribute("height", height); canvas.getSVGDocument().appendChild(group); return canvas; } else { return PlotKit.SVGRenderer.prototype.createSVGElement("svg", attrs); } }; PlotKit.SVGRenderer.isSupported = function() { var isOpera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1); var ieVersion = navigator.appVersion.match(/MSIE (\d\.\d)/); var safariVersion = navigator.userAgent.match(/AppleWebKit\/(\d+)/); var operaVersion = navigator.userAgent.match(/Opera\/(\d*\.\d*)/); var mozillaVersion = navigator.userAgent.match(/rv:(\d*\.\d*).*Gecko/); var svgFeature = "http://www.w3.org/TR/SVG11/feature#SVG"; if (ieVersion && (ieVersion[1] >= 6) && !isOpera) { return document.implementation.hasFeature(svgFeature,"1.1"); /* var dummysvg = document.createElement(''); try { dummysvg.getSVGDocument(); dummysvg = null; return true; } catch (e) { return false; } */ } /* support not really there yet. no text and paths are buggy if (safariVersion && (safariVersion[1] > 419)) return true; */ if (operaVersion && (operaVersion[1] > 8.9)) return true if (mozillaVersion && (mozillaVersion > 1.7)) return true; return false; }; // Namespace Iniitialisation PlotKit.SVG = {} PlotKit.SVG.SVGRenderer = PlotKit.SVGRenderer; PlotKit.SVG.EXPORT = [ "SVGRenderer" ]; PlotKit.SVG.EXPORT_OK = [ "SVGRenderer" ]; PlotKit.SVG.__new__ = function() { var m = MochiKit.Base; m.nameFunctions(this); this.EXPORT_TAGS = { ":common": this.EXPORT, ":all": m.concat(this.EXPORT, this.EXPORT_OK) }; }; PlotKit.SVG.__new__(); MochiKit.Base._exportSymbols(this, PlotKit.SVG); SABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/src/EasyPlot.js0000644000000000000000000001151212701006716024335 0ustar rootroot/* PlotKit EasyPlot ================ User friendly wrapper around the common plotting functions. Copyright --------- Copyright 2005,2006 (c) Alastair Tse For use under the BSD license. */ try { if (typeof(PlotKit.CanvasRenderer) == 'undefined') { throw "" } } catch (e) { throw "PlotKit.EasyPlot depends on all of PlotKit's components"; } // -------------------------------------------------------------------- // Start of EasyPlot definition // -------------------------------------------------------------------- if (typeof(PlotKit.EasyPlot) == 'undefined') { PlotKit.EasyPlot = {}; } PlotKit.EasyPlot.NAME = "PlotKit.EasyPlot"; PlotKit.EasyPlot.VERSION = PlotKit.VERSION; PlotKit.EasyPlot.__repr__ = function() { return "[" + this.NAME + " " + this.VERSION + "]"; }; PlotKit.EasyPlot.toString = function() { return this.__repr__(); } // -------------------------------------------------------------------- // Start of EasyPlot definition // -------------------------------------------------------------------- PlotKit.EasyPlot = function(style, options, divElem, datasources) { this.layout = new Layout(style, options); this.divElem = divElem; this.width = parseInt(divElem.getAttribute('width')); this.height = parseInt(divElem.getAttribute('height')); this.deferredCount = 0; // make sure we have non-zero width if (this.width < 1) { this.width = this.divElem.width ? this.divElem.width : 300; } if (this.height < 1) { this.height = this.divElem.height ? this.divElem.height : 300; } // load data sources if (isArrayLike(datasources)) { for (var i = 0; i < datasources.length; i++) { if (typeof(datasources[i]) == "string") { this.deferredCount++; // load CSV via ajax var d = MochiKit.Async.doSimpleXMLHttpRequest(datasources[i]); d.addCallback(MochiKit.Base.bind(PlotKit.EasyPlot.onDataLoaded, this)); } else if (isArrayLike(datasources[i])) { this.layout.addDataset("data-" + i, datasources[i]); } } } else if (!isUndefinedOrNull(datasources)) { throw "Passed datasources are not Array like"; } // setup canvas to render if (CanvasRenderer.isSupported()) { this.element = CANVAS({"id": this.divElem.getAttribute("id") + "-canvas", "width": this.width, "height": this.height}, ""); this.divElem.appendChild(this.element); this.renderer = new SweetCanvasRenderer(this.element, this.layout, options); } else if (SVGRenderer.isSupported()) { this.element = SVGRenderer.SVG({"id": this.divElem.getAttribute("id") + "-svg", "width": this.width, "height": this.height, "version": "1.1", "baseProfile": "full"}, ""); this.divElem.appendChild(this.element); this.renderer = new SweetSVGRenderer(this.element, this.layout, options); } if ((this.deferredCount == 0) && (PlotKit.Base.keys(this.layout.datasets).length > 0)) { this.layout.evaluate(); this.renderer.clear(); this.renderer.render(); } }; PlotKit.EasyPlot.onDataLoaded = function(request) { // very primitive CSV parser, should fix to make it more compliant. var table = new Array(); var lines = request.responseText.split('\n'); for (var i = 0; i < lines.length; i++) { var stripped = MochiKit.Format.strip(lines[i]); if ((stripped.length > 1) && (stripped.charAt(0) != '#')) { table.push(stripped.split(',')); } } this.layout.addDataset("data-ajax-" + this.deferredCount, table); this.deferredCount--; if ((this.deferredCount == 0) && (PlotKit.Base.keys(this.layout.datasets).length > 0)) { this.layout.evaluate(); this.renderer.clear(); this.renderer.render(); } }; PlotKit.EasyPlot.prototype.reload = function() { this.layout.evaluate(); this.renderer.clear(); this.renderer.render(); }; // Namespace Iniitialisation PlotKit.EasyPlotModule = {}; PlotKit.EasyPlotModule.EasyPlot = PlotKit.EasyPlot; PlotKit.EasyPlotModule.EXPORT = [ "EasyPlot" ]; PlotKit.EasyPlotModule.EXPORT_OK = []; PlotKit.EasyPlotModule.__new__ = function() { var m = MochiKit.Base; m.nameFunctions(this); this.EXPORT_TAGS = { ":common": this.EXPORT, ":all": m.concat(this.EXPORT, this.EXPORT_OK) }; }; PlotKit.EasyPlotModule.__new__(); MochiKit.Base._exportSymbols(this, PlotKit.EasyPlotModule); SABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/src/README0000644000000000000000000000024712701006716023122 0ustar rootrootThis directory holds sources for minified javascript files, for Debian policy compliance reasons. # interfaces/smpl/templates/static/PlotKit/PlotKit.js PlotKit 0.9.1 SABnzbd-2.3.2/interfaces/smpl/templates/static/PlotKit/src/SweetCanvas.js0000644000000000000000000002561412701006716025030 0ustar rootroot/* PlotKit Sweet Canvas Renderer ============================= Canvas Renderer for PlotKit which looks pretty! Copyright --------- Copyright 2005,2006 (c) Alastair Tse For use under the BSD license. */ // ------------------------------------------------------------------------- // Check required components // ------------------------------------------------------------------------- try { if (typeof(PlotKit.CanvasRenderer) == 'undefined') { throw ""; } } catch (e) { throw "SweetCanvas depends on MochiKit.{Base,Color,DOM,Format} and PlotKit.{Layout, Canvas}" } if (typeof(PlotKit.SweetCanvasRenderer) == 'undefined') { PlotKit.SweetCanvasRenderer = {}; } PlotKit.SweetCanvasRenderer = function(element, layout, options) { if (arguments.length > 0) { this.__init__(element, layout, options); } }; PlotKit.SweetCanvasRenderer.NAME = "PlotKit.SweetCanvasRenderer"; PlotKit.SweetCanvasRenderer.VERSION = PlotKit.VERSION; PlotKit.SweetCanvasRenderer.__repr__ = function() { return "[" + this.NAME + " " + this.VERSION + "]"; }; PlotKit.SweetCanvasRenderer.toString = function() { return this.__repr__(); }; // --------------------------------------------------------------------- // Subclassing Magic // --------------------------------------------------------------------- PlotKit.SweetCanvasRenderer.prototype = new PlotKit.CanvasRenderer(); PlotKit.SweetCanvasRenderer.prototype.constructor = PlotKit.SweetCanvasRenderer; PlotKit.SweetCanvasRenderer.__super__ = PlotKit.CanvasRenderer.prototype; // --------------------------------------------------------------------- // Constructor // --------------------------------------------------------------------- PlotKit.SweetCanvasRenderer.prototype.__init__ = function(el, layout, opts) { var moreOpts = PlotKit.Base.officeBlue(); MochiKit.Base.update(moreOpts, opts); PlotKit.SweetCanvasRenderer.__super__.__init__.call(this, el, layout, moreOpts); }; // --------------------------------------------------------------------- // Extended Plotting Functions // --------------------------------------------------------------------- PlotKit.SweetCanvasRenderer.prototype._renderBarChart = function() { var bind = MochiKit.Base.bind; var shadowColor = Color.blackColor().colorWithAlpha(0.1).toRGBString(); var prepareFakeShadow = function(context, x, y, w, h) { context.fillStyle = shadowColor; context.fillRect(x-2, y-2, w+4, h+2); context.fillStyle = shadowColor; context.fillRect(x-1, y-1, w+2, h+1); }; var colorCount = this.options.colorScheme.length; var colorScheme = this.options.colorScheme; var setNames = PlotKit.Base.keys(this.layout.datasets); var setCount = setNames.length; var chooseColor = function(name) { for (var i = 0; i < setCount; i++) { if (name == setNames[i]) return colorScheme[i%colorCount]; } return colorScheme[0]; }; var drawRect = function(context, bar) { var x = this.area.w * bar.x + this.area.x; var y = this.area.h * bar.y + this.area.y; var w = this.area.w * bar.w; var h = this.area.h * bar.h; if ((w < 1) || (h < 1)) return; context.save(); context.shadowBlur = 5.0; context.shadowColor = Color.fromHexString("#888888").toRGBString(); if (this.isIE) { context.save(); context.fillStyle = "#cccccc"; context.fillRect(x-2, y-2, w+4, h+2); context.restore(); } else { prepareFakeShadow(context, x, y, w, h); } if (this.options.shouldFill) { context.fillStyle = chooseColor(bar.name).toRGBString(); context.fillRect(x, y, w, h); } context.shadowBlur = 0; context.strokeStyle = Color.whiteColor().toRGBString(); context.lineWidth = 2.0; if (this.options.shouldStroke) { context.strokeRect(x, y, w, h); } context.restore(); }; this._renderBarChartWrap(this.layout.bars, bind(drawRect, this)); }; PlotKit.SweetCanvasRenderer.prototype._renderLineChart = function() { var context = this.element.getContext("2d"); var colorCount = this.options.colorScheme.length; var colorScheme = this.options.colorScheme; var setNames = PlotKit.Base.keys(this.layout.datasets); var setCount = setNames.length; var bind = MochiKit.Base.bind; for (var i = 0; i < setCount; i++) { var setName = setNames[i]; var color = colorScheme[i%colorCount]; var strokeX = this.options.strokeColorTransform; // setup graphics context context.save(); // create paths var makePath = function(ctx) { ctx.beginPath(); ctx.moveTo(this.area.x, this.area.y + this.area.h); var addPoint = function(ctx_, point) { if (point.name == setName) ctx_.lineTo(this.area.w * point.x + this.area.x, this.area.h * point.y + this.area.y); }; MochiKit.Iter.forEach(this.layout.points, partial(addPoint, ctx), this); ctx.lineTo(this.area.w + this.area.x, this.area.h + this.area.y); ctx.lineTo(this.area.x, this.area.y + this.area.h); ctx.closePath(); }; // faux shadow for firefox if (this.options.shouldFill) { context.save(); if (this.isIE) { context.fillStyle = "#cccccc"; } else { context.fillStyle = Color.blackColor().colorWithAlpha(0.2).toRGBString(); } context.translate(-1, -2); bind(makePath, this)(context); if (this.options.shouldFill) { context.fill(); } context.restore(); } context.shadowBlur = 5.0; context.shadowColor = Color.fromHexString("#888888").toRGBString(); context.fillStyle = color.toRGBString(); context.lineWidth = 2.0; context.strokeStyle = Color.whiteColor().toRGBString(); if (this.options.shouldFill) { bind(makePath, this)(context); context.fill(); } if (this.options.shouldStroke) { bind(makePath, this)(context); context.stroke(); } context.restore(); } }; PlotKit.SweetCanvasRenderer.prototype._renderPieChart = function() { var context = this.element.getContext("2d"); var colorCount = this.options.colorScheme.length; var slices = this.layout.slices; var centerx = this.area.x + this.area.w * 0.5; var centery = this.area.y + this.area.h * 0.5; var radius = Math.min(this.area.w * this.options.pieRadius, this.area.h * this.options.pieRadius); if (this.isIE) { centerx = parseInt(centerx); centery = parseInt(centery); radius = parseInt(radius); } // NOTE NOTE!! Canvas Tag draws the circle clockwise from the y = 0, x = 1 // so we have to subtract 90 degrees to make it start at y = 1, x = 0 if (!this.isIE) { context.save(); var shadowColor = Color.blackColor().colorWithAlpha(0.2); context.fillStyle = shadowColor.toRGBString(); context.shadowBlur = 5.0; context.shadowColor = Color.fromHexString("#888888").toRGBString(); context.translate(1, 1); context.beginPath(); context.moveTo(centerx, centery); context.arc(centerx, centery, radius + 2, 0, Math.PI*2, false); context.closePath(); context.fill(); context.restore(); } context.save(); context.strokeStyle = Color.whiteColor().toRGBString(); context.lineWidth = 2.0; for (var i = 0; i < slices.length; i++) { var color = this.options.colorScheme[i%colorCount]; context.fillStyle = color.toRGBString(); var makePath = function() { context.beginPath(); context.moveTo(centerx, centery); context.arc(centerx, centery, radius, slices[i].startAngle - Math.PI/2, slices[i].endAngle - Math.PI/2, false); context.lineTo(centerx, centery); context.closePath(); }; if (Math.abs(slices[i].startAngle - slices[i].endAngle) > 0.0001) { if (this.options.shouldFill) { makePath(); context.fill(); } if (this.options.shouldStroke) { makePath(); context.stroke(); } } } context.restore(); }; PlotKit.SweetCanvasRenderer.prototype._renderBackground = function() { var context = this.element.getContext("2d"); if (this.layout.style == "bar" || this.layout.style == "line") { context.save(); context.fillStyle = this.options.backgroundColor.toRGBString(); context.fillRect(this.area.x, this.area.y, this.area.w, this.area.h); context.strokeStyle = this.options.axisLineColor.toRGBString(); context.lineWidth = 1.0; var ticks = this.layout.yticks; var horiz = false; if (this.layout.style == "bar" && this.layout.options.barOrientation == "horizontal") { ticks = this.layout.xticks; horiz = true; } for (var i = 0; i < ticks.length; i++) { var x1 = 0; var y1 = 0; var x2 = 0; var y2 = 0; if (horiz) { x1 = ticks[i][0] * this.area.w + this.area.x; y1 = this.area.y; x2 = x1; y2 = y1 + this.area.h; } else { x1 = this.area.x; y1 = ticks[i][0] * this.area.h + this.area.y; x2 = x1 + this.area.w; y2 = y1; } context.beginPath(); context.moveTo(x1, y1); context.lineTo(x2, y2); context.closePath(); context.stroke(); } context.restore(); } else { PlotKit.SweetCanvasRenderer.__super__._renderBackground.call(this); } }; // Namespace Iniitialisation PlotKit.SweetCanvas = {} PlotKit.SweetCanvas.SweetCanvasRenderer = PlotKit.SweetCanvasRenderer; PlotKit.SweetCanvas.EXPORT = [ "SweetCanvasRenderer" ]; PlotKit.SweetCanvas.EXPORT_OK = [ "SweetCanvasRenderer" ]; PlotKit.SweetCanvas.__new__ = function() { var m = MochiKit.Base; m.nameFunctions(this); this.EXPORT_TAGS = { ":common": this.EXPORT, ":all": m.concat(this.EXPORT, this.EXPORT_OK) }; }; PlotKit.SweetCanvas.__new__(); MochiKit.Base._exportSymbols(this, PlotKit.SweetCanvas); SABnzbd-2.3.2/interfaces/Config/0000755000000000000000000000000013224674740015040 5ustar rootrootSABnzbd-2.3.2/interfaces/Config/templates/0000755000000000000000000000000013224674740017036 5ustar rootrootSABnzbd-2.3.2/interfaces/Config/templates/staticcfg/0000755000000000000000000000000013224674746021013 5ustar rootrootSABnzbd-2.3.2/interfaces/Config/templates/staticcfg/js/0000755000000000000000000000000013224674740021421 5ustar rootrootSABnzbd-2.3.2/interfaces/Config/templates/staticcfg/js/src/0000755000000000000000000000000013224674746022216 5ustar rootrootSABnzbd-2.3.2/interfaces/Config/templates/staticcfg/js/src/jquery.tablesort.js0000777000000000000000000000000013224674744032534 2jquery.tablesort_0.0.11.jsustar rootrootSABnzbd-2.3.2/interfaces/Config/templates/staticcfg/js/src/chartist_0.11.0.js0000644000000000000000000053405513147612210025164 0ustar rootroot(function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module unless amdModuleId is set define('Chartist', [], function () { return (root['Chartist'] = factory()); }); } else if (typeof module === 'object' && module.exports) { // Node. Does not work with strict CommonJS, but // only CommonJS-like environments that support module.exports, // like Node. module.exports = factory(); } else { root['Chartist'] = factory(); } }(this, function () { /* Chartist.js 0.11.0 * Copyright © 2017 Gion Kunz * Free to use under either the WTFPL license or the MIT license. * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT */ /** * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules. * * @module Chartist.Core */ var Chartist = { version: '0.11.0' }; (function (window, document, Chartist) { 'use strict'; /** * This object contains all namespaces used within Chartist. * * @memberof Chartist.Core * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}} */ Chartist.namespaces = { svg: 'http://www.w3.org/2000/svg', xmlns: 'http://www.w3.org/2000/xmlns/', xhtml: 'http://www.w3.org/1999/xhtml', xlink: 'http://www.w3.org/1999/xlink', ct: 'http://gionkunz.github.com/chartist-js/ct' }; /** * Helps to simplify functional style code * * @memberof Chartist.Core * @param {*} n This exact value will be returned by the noop function * @return {*} The same value that was provided to the n parameter */ Chartist.noop = function (n) { return n; }; /** * Generates a-z from a number 0 to 26 * * @memberof Chartist.Core * @param {Number} n A number from 0 to 26 that will result in a letter a-z * @return {String} A character from a-z based on the input number n */ Chartist.alphaNumerate = function (n) { // Limit to a-z return String.fromCharCode(97 + n % 26); }; /** * Simple recursive object extend * * @memberof Chartist.Core * @param {Object} target Target object where the source will be merged into * @param {Object...} sources This object (objects) will be merged into target and then target is returned * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source */ Chartist.extend = function (target) { var i, source, sourceProp; target = target || {}; for (i = 1; i < arguments.length; i++) { source = arguments[i]; for (var prop in source) { sourceProp = source[prop]; if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) { target[prop] = Chartist.extend(target[prop], sourceProp); } else { target[prop] = sourceProp; } } } return target; }; /** * Replaces all occurrences of subStr in str with newSubStr and returns a new string. * * @memberof Chartist.Core * @param {String} str * @param {String} subStr * @param {String} newSubStr * @return {String} */ Chartist.replaceAll = function(str, subStr, newSubStr) { return str.replace(new RegExp(subStr, 'g'), newSubStr); }; /** * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified. * * @memberof Chartist.Core * @param {Number} value * @param {String} unit * @return {String} Returns the passed number value with unit. */ Chartist.ensureUnit = function(value, unit) { if(typeof value === 'number') { value = value + unit; } return value; }; /** * Converts a number or string to a quantity object. * * @memberof Chartist.Core * @param {String|Number} input * @return {Object} Returns an object containing the value as number and the unit as string. */ Chartist.quantity = function(input) { if (typeof input === 'string') { var match = (/^(\d+)\s*(.*)$/g).exec(input); return { value : +match[1], unit: match[2] || undefined }; } return { value: input }; }; /** * This is a wrapper around document.querySelector that will return the query if it's already of type Node * * @memberof Chartist.Core * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly * @return {Node} */ Chartist.querySelector = function(query) { return query instanceof Node ? query : document.querySelector(query); }; /** * Functional style helper to produce array with given length initialized with undefined values * * @memberof Chartist.Core * @param length * @return {Array} */ Chartist.times = function(length) { return Array.apply(null, new Array(length)); }; /** * Sum helper to be used in reduce functions * * @memberof Chartist.Core * @param previous * @param current * @return {*} */ Chartist.sum = function(previous, current) { return previous + (current ? current : 0); }; /** * Multiply helper to be used in `Array.map` for multiplying each value of an array with a factor. * * @memberof Chartist.Core * @param {Number} factor * @returns {Function} Function that can be used in `Array.map` to multiply each value in an array */ Chartist.mapMultiply = function(factor) { return function(num) { return num * factor; }; }; /** * Add helper to be used in `Array.map` for adding a addend to each value of an array. * * @memberof Chartist.Core * @param {Number} addend * @returns {Function} Function that can be used in `Array.map` to add a addend to each value in an array */ Chartist.mapAdd = function(addend) { return function(num) { return num + addend; }; }; /** * Map for multi dimensional arrays where their nested arrays will be mapped in serial. The output array will have the length of the largest nested array. The callback function is called with variable arguments where each argument is the nested array value (or undefined if there are no more values). * * @memberof Chartist.Core * @param arr * @param cb * @return {Array} */ Chartist.serialMap = function(arr, cb) { var result = [], length = Math.max.apply(null, arr.map(function(e) { return e.length; })); Chartist.times(length).forEach(function(e, index) { var args = arr.map(function(e) { return e[index]; }); result[index] = cb.apply(null, args); }); return result; }; /** * This helper function can be used to round values with certain precision level after decimal. This is used to prevent rounding errors near float point precision limit. * * @memberof Chartist.Core * @param {Number} value The value that should be rounded with precision * @param {Number} [digits] The number of digits after decimal used to do the rounding * @returns {number} Rounded value */ Chartist.roundWithPrecision = function(value, digits) { var precision = Math.pow(10, digits || Chartist.precision); return Math.round(value * precision) / precision; }; /** * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number. * * @memberof Chartist.Core * @type {number} */ Chartist.precision = 8; /** * A map with characters to escape for strings to be safely used as attribute values. * * @memberof Chartist.Core * @type {Object} */ Chartist.escapingMap = { '&': '&', '<': '<', '>': '>', '"': '"', '\'': ''' }; /** * This function serializes arbitrary data to a string. In case of data that can't be easily converted to a string, this function will create a wrapper object and serialize the data using JSON.stringify. The outcoming string will always be escaped using Chartist.escapingMap. * If called with null or undefined the function will return immediately with null or undefined. * * @memberof Chartist.Core * @param {Number|String|Object} data * @return {String} */ Chartist.serialize = function(data) { if(data === null || data === undefined) { return data; } else if(typeof data === 'number') { data = ''+data; } else if(typeof data === 'object') { data = JSON.stringify({data: data}); } return Object.keys(Chartist.escapingMap).reduce(function(result, key) { return Chartist.replaceAll(result, key, Chartist.escapingMap[key]); }, data); }; /** * This function de-serializes a string previously serialized with Chartist.serialize. The string will always be unescaped using Chartist.escapingMap before it's returned. Based on the input value the return type can be Number, String or Object. JSON.parse is used with try / catch to see if the unescaped string can be parsed into an Object and this Object will be returned on success. * * @memberof Chartist.Core * @param {String} data * @return {String|Number|Object} */ Chartist.deserialize = function(data) { if(typeof data !== 'string') { return data; } data = Object.keys(Chartist.escapingMap).reduce(function(result, key) { return Chartist.replaceAll(result, Chartist.escapingMap[key], key); }, data); try { data = JSON.parse(data); data = data.data !== undefined ? data.data : data; } catch(e) {} return data; }; /** * Create or reinitialize the SVG element for the chart * * @memberof Chartist.Core * @param {Node} container The containing DOM Node object that will be used to plant the SVG element * @param {String} width Set the width of the SVG element. Default is 100% * @param {String} height Set the height of the SVG element. Default is 100% * @param {String} className Specify a class to be added to the SVG element * @return {Object} The created/reinitialized SVG element */ Chartist.createSvg = function (container, width, height, className) { var svg; width = width || '100%'; height = height || '100%'; // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/ Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) { return svg.getAttributeNS(Chartist.namespaces.xmlns, 'ct'); }).forEach(function removePreviousElement(svg) { container.removeChild(svg); }); // Create svg object with width and height or use 100% as default svg = new Chartist.Svg('svg').attr({ width: width, height: height }).addClass(className); svg._node.style.width = width; svg._node.style.height = height; // Add the DOM node to our container container.appendChild(svg._node); return svg; }; /** * Ensures that the data object passed as second argument to the charts is present and correctly initialized. * * @param {Object} data The data object that is passed as second argument to the charts * @return {Object} The normalized data object */ Chartist.normalizeData = function(data, reverse, multi) { var labelCount; var output = { raw: data, normalized: {} }; // Check if we should generate some labels based on existing series data output.normalized.series = Chartist.getDataArray({ series: data.series || [] }, reverse, multi); // If all elements of the normalized data array are arrays we're dealing with // multi series data and we need to find the largest series if they are un-even if (output.normalized.series.every(function(value) { return value instanceof Array; })) { // Getting the series with the the most elements labelCount = Math.max.apply(null, output.normalized.series.map(function(series) { return series.length; })); } else { // We're dealing with Pie data so we just take the normalized array length labelCount = output.normalized.series.length; } output.normalized.labels = (data.labels || []).slice(); // Padding the labels to labelCount with empty strings Array.prototype.push.apply( output.normalized.labels, Chartist.times(Math.max(0, labelCount - output.normalized.labels.length)).map(function() { return ''; }) ); if(reverse) { Chartist.reverseData(output.normalized); } return output; }; /** * This function safely checks if an objects has an owned property. * * @param {Object} object The object where to check for a property * @param {string} property The property name * @returns {boolean} Returns true if the object owns the specified property */ Chartist.safeHasProperty = function(object, property) { return object !== null && typeof object === 'object' && object.hasOwnProperty(property); }; /** * Checks if a value is considered a hole in the data series. * * @param {*} value * @returns {boolean} True if the value is considered a data hole */ Chartist.isDataHoleValue = function(value) { return value === null || value === undefined || (typeof value === 'number' && isNaN(value)); }; /** * Reverses the series, labels and series data arrays. * * @memberof Chartist.Core * @param data */ Chartist.reverseData = function(data) { data.labels.reverse(); data.series.reverse(); for (var i = 0; i < data.series.length; i++) { if(typeof(data.series[i]) === 'object' && data.series[i].data !== undefined) { data.series[i].data.reverse(); } else if(data.series[i] instanceof Array) { data.series[i].reverse(); } } }; /** * Convert data series into plain array * * @memberof Chartist.Core * @param {Object} data The series object that contains the data to be visualized in the chart * @param {Boolean} [reverse] If true the whole data is reversed by the getDataArray call. This will modify the data object passed as first parameter. The labels as well as the series order is reversed. The whole series data arrays are reversed too. * @param {Boolean} [multi] Create a multi dimensional array from a series data array where a value object with `x` and `y` values will be created. * @return {Array} A plain array that contains the data to be visualized in the chart */ Chartist.getDataArray = function(data, reverse, multi) { // Recursively walks through nested arrays and convert string values to numbers and objects with value properties // to values. Check the tests in data core -> data normalization for a detailed specification of expected values function recursiveConvert(value) { if(Chartist.safeHasProperty(value, 'value')) { // We are dealing with value object notation so we need to recurse on value property return recursiveConvert(value.value); } else if(Chartist.safeHasProperty(value, 'data')) { // We are dealing with series object notation so we need to recurse on data property return recursiveConvert(value.data); } else if(value instanceof Array) { // Data is of type array so we need to recurse on the series return value.map(recursiveConvert); } else if(Chartist.isDataHoleValue(value)) { // We're dealing with a hole in the data and therefore need to return undefined // We're also returning undefined for multi value output return undefined; } else { // We need to prepare multi value output (x and y data) if(multi) { var multiValue = {}; // Single series value arrays are assumed to specify the Y-Axis value // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}] // If multi is a string then it's assumed that it specified which dimension should be filled as default if(typeof multi === 'string') { multiValue[multi] = Chartist.getNumberOrUndefined(value); } else { multiValue.y = Chartist.getNumberOrUndefined(value); } multiValue.x = value.hasOwnProperty('x') ? Chartist.getNumberOrUndefined(value.x) : multiValue.x; multiValue.y = value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : multiValue.y; return multiValue; } else { // We can return simple data return Chartist.getNumberOrUndefined(value); } } } return data.series.map(recursiveConvert); }; /** * Converts a number into a padding object. * * @memberof Chartist.Core * @param {Object|Number} padding * @param {Number} [fallback] This value is used to fill missing values if a incomplete padding object was passed * @returns {Object} Returns a padding object containing top, right, bottom, left properties filled with the padding number passed in as argument. If the argument is something else than a number (presumably already a correct padding object) then this argument is directly returned. */ Chartist.normalizePadding = function(padding, fallback) { fallback = fallback || 0; return typeof padding === 'number' ? { top: padding, right: padding, bottom: padding, left: padding } : { top: typeof padding.top === 'number' ? padding.top : fallback, right: typeof padding.right === 'number' ? padding.right : fallback, bottom: typeof padding.bottom === 'number' ? padding.bottom : fallback, left: typeof padding.left === 'number' ? padding.left : fallback }; }; Chartist.getMetaData = function(series, index) { var value = series.data ? series.data[index] : series[index]; return value ? value.meta : undefined; }; /** * Calculate the order of magnitude for the chart scale * * @memberof Chartist.Core * @param {Number} value The value Range of the chart * @return {Number} The order of magnitude */ Chartist.orderOfMagnitude = function (value) { return Math.floor(Math.log(Math.abs(value)) / Math.LN10); }; /** * Project a data length into screen coordinates (pixels) * * @memberof Chartist.Core * @param {Object} axisLength The svg element for the chart * @param {Number} length Single data value from a series array * @param {Object} bounds All the values to set the bounds of the chart * @return {Number} The projected data length in pixels */ Chartist.projectLength = function (axisLength, length, bounds) { return length / bounds.range * axisLength; }; /** * Get the height of the area in the chart for the data series * * @memberof Chartist.Core * @param {Object} svg The svg element for the chart * @param {Object} options The Object that contains all the optional values for the chart * @return {Number} The height of the area in the chart for the data series */ Chartist.getAvailableHeight = function (svg, options) { return Math.max((Chartist.quantity(options.height).value || svg.height()) - (options.chartPadding.top + options.chartPadding.bottom) - options.axisX.offset, 0); }; /** * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart. * * @memberof Chartist.Core * @param {Array} data The array that contains the data to be visualized in the chart * @param {Object} options The Object that contains the chart options * @param {String} dimension Axis dimension 'x' or 'y' used to access the correct value and high / low configuration * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart. */ Chartist.getHighLow = function (data, options, dimension) { // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred options = Chartist.extend({}, options, dimension ? options['axis' + dimension.toUpperCase()] : {}); var highLow = { high: options.high === undefined ? -Number.MAX_VALUE : +options.high, low: options.low === undefined ? Number.MAX_VALUE : +options.low }; var findHigh = options.high === undefined; var findLow = options.low === undefined; // Function to recursively walk through arrays and find highest and lowest number function recursiveHighLow(data) { if(data === undefined) { return undefined; } else if(data instanceof Array) { for (var i = 0; i < data.length; i++) { recursiveHighLow(data[i]); } } else { var value = dimension ? +data[dimension] : +data; if (findHigh && value > highLow.high) { highLow.high = value; } if (findLow && value < highLow.low) { highLow.low = value; } } } // Start to find highest and lowest number recursively if(findHigh || findLow) { recursiveHighLow(data); } // Overrides of high / low based on reference value, it will make sure that the invisible reference value is // used to generate the chart. This is useful when the chart always needs to contain the position of the // invisible reference value in the view i.e. for bipolar scales. if (options.referenceValue || options.referenceValue === 0) { highLow.high = Math.max(options.referenceValue, highLow.high); highLow.low = Math.min(options.referenceValue, highLow.low); } // If high and low are the same because of misconfiguration or flat data (only the same value) we need // to set the high or low to 0 depending on the polarity if (highLow.high <= highLow.low) { // If both values are 0 we set high to 1 if (highLow.low === 0) { highLow.high = 1; } else if (highLow.low < 0) { // If we have the same negative value for the bounds we set bounds.high to 0 highLow.high = 0; } else if (highLow.high > 0) { // If we have the same positive value for the bounds we set bounds.low to 0 highLow.low = 0; } else { // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors highLow.high = 1; highLow.low = 0; } } return highLow; }; /** * Checks if a value can be safely coerced to a number. This includes all values except null which result in finite numbers when coerced. This excludes NaN, since it's not finite. * * @memberof Chartist.Core * @param value * @returns {Boolean} */ Chartist.isNumeric = function(value) { return value === null ? false : isFinite(value); }; /** * Returns true on all falsey values except the numeric value 0. * * @memberof Chartist.Core * @param value * @returns {boolean} */ Chartist.isFalseyButZero = function(value) { return !value && value !== 0; }; /** * Returns a number if the passed parameter is a valid number or the function will return undefined. On all other values than a valid number, this function will return undefined. * * @memberof Chartist.Core * @param value * @returns {*} */ Chartist.getNumberOrUndefined = function(value) { return Chartist.isNumeric(value) ? +value : undefined; }; /** * Checks if provided value object is multi value (contains x or y properties) * * @memberof Chartist.Core * @param value */ Chartist.isMultiValue = function(value) { return typeof value === 'object' && ('x' in value || 'y' in value); }; /** * Gets a value from a dimension `value.x` or `value.y` while returning value directly if it's a valid numeric value. If the value is not numeric and it's falsey this function will return `defaultValue`. * * @memberof Chartist.Core * @param value * @param dimension * @param defaultValue * @returns {*} */ Chartist.getMultiValue = function(value, dimension) { if(Chartist.isMultiValue(value)) { return Chartist.getNumberOrUndefined(value[dimension || 'y']); } else { return Chartist.getNumberOrUndefined(value); } }; /** * Pollard Rho Algorithm to find smallest factor of an integer value. There are more efficient algorithms for factorization, but this one is quite efficient and not so complex. * * @memberof Chartist.Core * @param {Number} num An integer number where the smallest factor should be searched for * @returns {Number} The smallest integer factor of the parameter num. */ Chartist.rho = function(num) { if(num === 1) { return num; } function gcd(p, q) { if (p % q === 0) { return q; } else { return gcd(q, p % q); } } function f(x) { return x * x + 1; } var x1 = 2, x2 = 2, divisor; if (num % 2 === 0) { return 2; } do { x1 = f(x1) % num; x2 = f(f(x2)) % num; divisor = gcd(Math.abs(x1 - x2), num); } while (divisor === 1); return divisor; }; /** * Calculate and retrieve all the bounds for the chart and return them in one array * * @memberof Chartist.Core * @param {Number} axisLength The length of the Axis used for * @param {Object} highLow An object containing a high and low property indicating the value range of the chart. * @param {Number} scaleMinSpace The minimum projected length a step should result in * @param {Boolean} onlyInteger * @return {Object} All the values to set the bounds of the chart */ Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, onlyInteger) { var i, optimizationCounter = 0, newMin, newMax, bounds = { high: highLow.high, low: highLow.low }; bounds.valueRange = bounds.high - bounds.low; bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange); bounds.step = Math.pow(10, bounds.oom); bounds.min = Math.floor(bounds.low / bounds.step) * bounds.step; bounds.max = Math.ceil(bounds.high / bounds.step) * bounds.step; bounds.range = bounds.max - bounds.min; bounds.numberOfSteps = Math.round(bounds.range / bounds.step); // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace // If we are already below the scaleMinSpace value we will scale up var length = Chartist.projectLength(axisLength, bounds.step, bounds); var scaleUp = length < scaleMinSpace; var smallestFactor = onlyInteger ? Chartist.rho(bounds.range) : 0; // First check if we should only use integer steps and if step 1 is still larger than scaleMinSpace so we can use 1 if(onlyInteger && Chartist.projectLength(axisLength, 1, bounds) >= scaleMinSpace) { bounds.step = 1; } else if(onlyInteger && smallestFactor < bounds.step && Chartist.projectLength(axisLength, smallestFactor, bounds) >= scaleMinSpace) { // If step 1 was too small, we can try the smallest factor of range // If the smallest factor is smaller than the current bounds.step and the projected length of smallest factor // is larger than the scaleMinSpace we should go for it. bounds.step = smallestFactor; } else { // Trying to divide or multiply by 2 and find the best step value while (true) { if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) { bounds.step *= 2; } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) { bounds.step /= 2; if(onlyInteger && bounds.step % 1 !== 0) { bounds.step *= 2; break; } } else { break; } if(optimizationCounter++ > 1000) { throw new Error('Exceeded maximum number of iterations while optimizing scale step!'); } } } var EPSILON = 2.221E-16; bounds.step = Math.max(bounds.step, EPSILON); function safeIncrement(value, increment) { // If increment is too small use *= (1+EPSILON) as a simple nextafter if (value === (value += increment)) { value *= (1 + (increment > 0 ? EPSILON : -EPSILON)); } return value; } // Narrow min and max based on new step newMin = bounds.min; newMax = bounds.max; while (newMin + bounds.step <= bounds.low) { newMin = safeIncrement(newMin, bounds.step); } while (newMax - bounds.step >= bounds.high) { newMax = safeIncrement(newMax, -bounds.step); } bounds.min = newMin; bounds.max = newMax; bounds.range = bounds.max - bounds.min; var values = []; for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) { var value = Chartist.roundWithPrecision(i); if (value !== values[values.length - 1]) { values.push(value); } } bounds.values = values; return bounds; }; /** * Calculate cartesian coordinates of polar coordinates * * @memberof Chartist.Core * @param {Number} centerX X-axis coordinates of center point of circle segment * @param {Number} centerY X-axis coordinates of center point of circle segment * @param {Number} radius Radius of circle segment * @param {Number} angleInDegrees Angle of circle segment in degrees * @return {{x:Number, y:Number}} Coordinates of point on circumference */ Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) { var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; return { x: centerX + (radius * Math.cos(angleInRadians)), y: centerY + (radius * Math.sin(angleInRadians)) }; }; /** * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right * * @memberof Chartist.Core * @param {Object} svg The svg element for the chart * @param {Object} options The Object that contains all the optional values for the chart * @param {Number} [fallbackPadding] The fallback padding if partial padding objects are used * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements */ Chartist.createChartRect = function (svg, options, fallbackPadding) { var hasAxis = !!(options.axisX || options.axisY); var yAxisOffset = hasAxis ? options.axisY.offset : 0; var xAxisOffset = hasAxis ? options.axisX.offset : 0; // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0 var width = svg.width() || Chartist.quantity(options.width).value || 0; var height = svg.height() || Chartist.quantity(options.height).value || 0; var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding); // If settings were to small to cope with offset (legacy) and padding, we'll adjust width = Math.max(width, yAxisOffset + normalizedPadding.left + normalizedPadding.right); height = Math.max(height, xAxisOffset + normalizedPadding.top + normalizedPadding.bottom); var chartRect = { padding: normalizedPadding, width: function () { return this.x2 - this.x1; }, height: function () { return this.y1 - this.y2; } }; if(hasAxis) { if (options.axisX.position === 'start') { chartRect.y2 = normalizedPadding.top + xAxisOffset; chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); } else { chartRect.y2 = normalizedPadding.top; chartRect.y1 = Math.max(height - normalizedPadding.bottom - xAxisOffset, chartRect.y2 + 1); } if (options.axisY.position === 'start') { chartRect.x1 = normalizedPadding.left + yAxisOffset; chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); } else { chartRect.x1 = normalizedPadding.left; chartRect.x2 = Math.max(width - normalizedPadding.right - yAxisOffset, chartRect.x1 + 1); } } else { chartRect.x1 = normalizedPadding.left; chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1); chartRect.y2 = normalizedPadding.top; chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1); } return chartRect; }; /** * Creates a grid line based on a projected value. * * @memberof Chartist.Core * @param position * @param index * @param axis * @param offset * @param length * @param group * @param classes * @param eventEmitter */ Chartist.createGrid = function(position, index, axis, offset, length, group, classes, eventEmitter) { var positionalData = {}; positionalData[axis.units.pos + '1'] = position; positionalData[axis.units.pos + '2'] = position; positionalData[axis.counterUnits.pos + '1'] = offset; positionalData[axis.counterUnits.pos + '2'] = offset + length; var gridElement = group.elem('line', positionalData, classes.join(' ')); // Event for grid draw eventEmitter.emit('draw', Chartist.extend({ type: 'grid', axis: axis, index: index, group: group, element: gridElement }, positionalData) ); }; /** * Creates a grid background rect and emits the draw event. * * @memberof Chartist.Core * @param gridGroup * @param chartRect * @param className * @param eventEmitter */ Chartist.createGridBackground = function (gridGroup, chartRect, className, eventEmitter) { var gridBackground = gridGroup.elem('rect', { x: chartRect.x1, y: chartRect.y2, width: chartRect.width(), height: chartRect.height(), }, className, true); // Event for grid background draw eventEmitter.emit('draw', { type: 'gridBackground', group: gridGroup, element: gridBackground }); }; /** * Creates a label based on a projected value and an axis. * * @memberof Chartist.Core * @param position * @param length * @param index * @param labels * @param axis * @param axisOffset * @param labelOffset * @param group * @param classes * @param useForeignObject * @param eventEmitter */ Chartist.createLabel = function(position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) { var labelElement; var positionalData = {}; positionalData[axis.units.pos] = position + labelOffset[axis.units.pos]; positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos]; positionalData[axis.units.len] = length; positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10); if(useForeignObject) { // We need to set width and height explicitly to px as span will not expand with width and height being // 100% in all browsers var content = document.createElement('span'); content.className = classes.join(' '); content.setAttribute('xmlns', Chartist.namespaces.xhtml); content.innerText = labels[index]; content.style[axis.units.len] = Math.round(positionalData[axis.units.len]) + 'px'; content.style[axis.counterUnits.len] = Math.round(positionalData[axis.counterUnits.len]) + 'px'; labelElement = group.foreignObject(content, Chartist.extend({ style: 'overflow: visible;' }, positionalData)); } else { labelElement = group.elem('text', positionalData, classes.join(' ')).text(labels[index]); } eventEmitter.emit('draw', Chartist.extend({ type: 'label', axis: axis, index: index, group: group, element: labelElement, text: labels[index] }, positionalData)); }; /** * Helper to read series specific options from options object. It automatically falls back to the global option if * there is no option in the series options. * * @param {Object} series Series object * @param {Object} options Chartist options object * @param {string} key The options key that should be used to obtain the options * @returns {*} */ Chartist.getSeriesOption = function(series, options, key) { if(series.name && options.series && options.series[series.name]) { var seriesOptions = options.series[series.name]; return seriesOptions.hasOwnProperty(key) ? seriesOptions[key] : options[key]; } else { return options[key]; } }; /** * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches * * @memberof Chartist.Core * @param {Object} options Options set by user * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events * @return {Object} The consolidated options object from the defaults, base and matching responsive options */ Chartist.optionsProvider = function (options, responsiveOptions, eventEmitter) { var baseOptions = Chartist.extend({}, options), currentOptions, mediaQueryListeners = [], i; function updateCurrentOptions(mediaEvent) { var previousOptions = currentOptions; currentOptions = Chartist.extend({}, baseOptions); if (responsiveOptions) { for (i = 0; i < responsiveOptions.length; i++) { var mql = window.matchMedia(responsiveOptions[i][0]); if (mql.matches) { currentOptions = Chartist.extend(currentOptions, responsiveOptions[i][1]); } } } if(eventEmitter && mediaEvent) { eventEmitter.emit('optionsChanged', { previousOptions: previousOptions, currentOptions: currentOptions }); } } function removeMediaQueryListeners() { mediaQueryListeners.forEach(function(mql) { mql.removeListener(updateCurrentOptions); }); } if (!window.matchMedia) { throw 'window.matchMedia not found! Make sure you\'re using a polyfill.'; } else if (responsiveOptions) { for (i = 0; i < responsiveOptions.length; i++) { var mql = window.matchMedia(responsiveOptions[i][0]); mql.addListener(updateCurrentOptions); mediaQueryListeners.push(mql); } } // Execute initially without an event argument so we get the correct options updateCurrentOptions(); return { removeMediaQueryListeners: removeMediaQueryListeners, getCurrentOptions: function getCurrentOptions() { return Chartist.extend({}, currentOptions); } }; }; /** * Splits a list of coordinates and associated values into segments. Each returned segment contains a pathCoordinates * valueData property describing the segment. * * With the default options, segments consist of contiguous sets of points that do not have an undefined value. Any * points with undefined values are discarded. * * **Options** * The following options are used to determine how segments are formed * ```javascript * var options = { * // If fillHoles is true, undefined values are simply discarded without creating a new segment. Assuming other options are default, this returns single segment. * fillHoles: false, * // If increasingX is true, the coordinates in all segments have strictly increasing x-values. * increasingX: false * }; * ``` * * @memberof Chartist.Core * @param {Array} pathCoordinates List of point coordinates to be split in the form [x1, y1, x2, y2 ... xn, yn] * @param {Array} values List of associated point values in the form [v1, v2 .. vn] * @param {Object} options Options set by user * @return {Array} List of segments, each containing a pathCoordinates and valueData property. */ Chartist.splitIntoSegments = function(pathCoordinates, valueData, options) { var defaultOptions = { increasingX: false, fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); var segments = []; var hole = true; for(var i = 0; i < pathCoordinates.length; i += 2) { // If this value is a "hole" we set the hole flag if(Chartist.getMultiValue(valueData[i / 2].value) === undefined) { // if(valueData[i / 2].value === undefined) { if(!options.fillHoles) { hole = true; } } else { if(options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i-2]) { // X is not increasing, so we need to make sure we start a new segment hole = true; } // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment if(hole) { segments.push({ pathCoordinates: [], valueData: [] }); // As we have a valid value now, we are not in a "hole" anymore hole = false; } // Add to the segment pathCoordinates and valueData segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]); segments[segments.length - 1].valueData.push(valueData[i / 2]); } } return segments; }; }(window, document, Chartist)); ;/** * Chartist path interpolation functions. * * @module Chartist.Interpolation */ /* global Chartist */ (function(window, document, Chartist) { 'use strict'; Chartist.Interpolation = {}; /** * This interpolation function does not smooth the path and the result is only containing lines and no curves. * * @example * var chart = new Chartist.Line('.ct-chart', { * labels: [1, 2, 3, 4, 5], * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.none({ * fillHoles: false * }) * }); * * * @memberof Chartist.Interpolation * @return {Function} */ Chartist.Interpolation.none = function(options) { var defaultOptions = { fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); return function none(pathCoordinates, valueData) { var path = new Chartist.Svg.Path(); var hole = true; for(var i = 0; i < pathCoordinates.length; i += 2) { var currX = pathCoordinates[i]; var currY = pathCoordinates[i + 1]; var currData = valueData[i / 2]; if(Chartist.getMultiValue(currData.value) !== undefined) { if(hole) { path.move(currX, currY, false, currData); } else { path.line(currX, currY, false, currData); } hole = false; } else if(!options.fillHoles) { hole = true; } } return path; }; }; /** * Simple smoothing creates horizontal handles that are positioned with a fraction of the length between two data points. You can use the divisor option to specify the amount of smoothing. * * Simple smoothing can be used instead of `Chartist.Smoothing.cardinal` if you'd like to get rid of the artifacts it produces sometimes. Simple smoothing produces less flowing lines but is accurate by hitting the points and it also doesn't swing below or above the given data point. * * All smoothing functions within Chartist are factory functions that accept an options parameter. The simple interpolation function accepts one configuration parameter `divisor`, between 1 and ∞, which controls the smoothing characteristics. * * @example * var chart = new Chartist.Line('.ct-chart', { * labels: [1, 2, 3, 4, 5], * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.simple({ * divisor: 2, * fillHoles: false * }) * }); * * * @memberof Chartist.Interpolation * @param {Object} options The options of the simple interpolation factory function. * @return {Function} */ Chartist.Interpolation.simple = function(options) { var defaultOptions = { divisor: 2, fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); var d = 1 / Math.max(1, options.divisor); return function simple(pathCoordinates, valueData) { var path = new Chartist.Svg.Path(); var prevX, prevY, prevData; for(var i = 0; i < pathCoordinates.length; i += 2) { var currX = pathCoordinates[i]; var currY = pathCoordinates[i + 1]; var length = (currX - prevX) * d; var currData = valueData[i / 2]; if(currData.value !== undefined) { if(prevData === undefined) { path.move(currX, currY, false, currData); } else { path.curve( prevX + length, prevY, currX - length, currY, currX, currY, false, currData ); } prevX = currX; prevY = currY; prevData = currData; } else if(!options.fillHoles) { prevX = currX = prevData = undefined; } } return path; }; }; /** * Cardinal / Catmull-Rome spline interpolation is the default smoothing function in Chartist. It produces nice results where the splines will always meet the points. It produces some artifacts though when data values are increased or decreased rapidly. The line may not follow a very accurate path and if the line should be accurate this smoothing function does not produce the best results. * * Cardinal splines can only be created if there are more than two data points. If this is not the case this smoothing will fallback to `Chartist.Smoothing.none`. * * All smoothing functions within Chartist are factory functions that accept an options parameter. The cardinal interpolation function accepts one configuration parameter `tension`, between 0 and 1, which controls the smoothing intensity. * * @example * var chart = new Chartist.Line('.ct-chart', { * labels: [1, 2, 3, 4, 5], * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.cardinal({ * tension: 1, * fillHoles: false * }) * }); * * @memberof Chartist.Interpolation * @param {Object} options The options of the cardinal factory function. * @return {Function} */ Chartist.Interpolation.cardinal = function(options) { var defaultOptions = { tension: 1, fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); var t = Math.min(1, Math.max(0, options.tension)), c = 1 - t; return function cardinal(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, { fillHoles: options.fillHoles }); if(!segments.length) { // If there were no segments return 'Chartist.Interpolation.none' return Chartist.Interpolation.none()([]); } else if(segments.length > 1) { // If the split resulted in more that one segment we need to interpolate each segment individually and join them // afterwards together into a single path. var paths = []; // For each segment we will recurse the cardinal function segments.forEach(function(segment) { paths.push(cardinal(segment.pathCoordinates, segment.valueData)); }); // Join the segment path data into a single path and return return Chartist.Svg.Path.join(paths); } else { // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first // segment pathCoordinates = segments[0].pathCoordinates; valueData = segments[0].valueData; // If less than two points we need to fallback to no smoothing if(pathCoordinates.length <= 4) { return Chartist.Interpolation.none()(pathCoordinates, valueData); } var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]), z; for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) { var p = [ {x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1]}, {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}, {x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3]}, {x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5]} ]; if (z) { if (!i) { p[0] = {x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1]}; } else if (iLen - 4 === i) { p[3] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; } else if (iLen - 2 === i) { p[2] = {x: +pathCoordinates[0], y: +pathCoordinates[1]}; p[3] = {x: +pathCoordinates[2], y: +pathCoordinates[3]}; } } else { if (iLen - 4 === i) { p[3] = p[2]; } else if (!i) { p[0] = {x: +pathCoordinates[i], y: +pathCoordinates[i + 1]}; } } path.curve( (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x), (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y), (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x), (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y), p[2].x, p[2].y, false, valueData[(i + 2) / 2] ); } return path; } }; }; /** * Monotone Cubic spline interpolation produces a smooth curve which preserves monotonicity. Unlike cardinal splines, the curve will not extend beyond the range of y-values of the original data points. * * Monotone Cubic splines can only be created if there are more than two data points. If this is not the case this smoothing will fallback to `Chartist.Smoothing.none`. * * The x-values of subsequent points must be increasing to fit a Monotone Cubic spline. If this condition is not met for a pair of adjacent points, then there will be a break in the curve between those data points. * * All smoothing functions within Chartist are factory functions that accept an options parameter. * * @example * var chart = new Chartist.Line('.ct-chart', { * labels: [1, 2, 3, 4, 5], * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.monotoneCubic({ * fillHoles: false * }) * }); * * @memberof Chartist.Interpolation * @param {Object} options The options of the monotoneCubic factory function. * @return {Function} */ Chartist.Interpolation.monotoneCubic = function(options) { var defaultOptions = { fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); return function monotoneCubic(pathCoordinates, valueData) { // First we try to split the coordinates into segments // This is necessary to treat "holes" in line charts var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, { fillHoles: options.fillHoles, increasingX: true }); if(!segments.length) { // If there were no segments return 'Chartist.Interpolation.none' return Chartist.Interpolation.none()([]); } else if(segments.length > 1) { // If the split resulted in more that one segment we need to interpolate each segment individually and join them // afterwards together into a single path. var paths = []; // For each segment we will recurse the monotoneCubic fn function segments.forEach(function(segment) { paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData)); }); // Join the segment path data into a single path and return return Chartist.Svg.Path.join(paths); } else { // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first // segment pathCoordinates = segments[0].pathCoordinates; valueData = segments[0].valueData; // If less than three points we need to fallback to no smoothing if(pathCoordinates.length <= 4) { return Chartist.Interpolation.none()(pathCoordinates, valueData); } var xs = [], ys = [], i, n = pathCoordinates.length / 2, ms = [], ds = [], dys = [], dxs = [], path; // Populate x and y coordinates into separate arrays, for readability for(i = 0; i < n; i++) { xs[i] = pathCoordinates[i * 2]; ys[i] = pathCoordinates[i * 2 + 1]; } // Calculate deltas and derivative for(i = 0; i < n - 1; i++) { dys[i] = ys[i + 1] - ys[i]; dxs[i] = xs[i + 1] - xs[i]; ds[i] = dys[i] / dxs[i]; } // Determine desired slope (m) at each point using Fritsch-Carlson method // See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation ms[0] = ds[0]; ms[n - 1] = ds[n - 2]; for(i = 1; i < n - 1; i++) { if(ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0)) { ms[i] = 0; } else { ms[i] = 3 * (dxs[i - 1] + dxs[i]) / ( (2 * dxs[i] + dxs[i - 1]) / ds[i - 1] + (dxs[i] + 2 * dxs[i - 1]) / ds[i]); if(!isFinite(ms[i])) { ms[i] = 0; } } } // Now build a path from the slopes path = new Chartist.Svg.Path().move(xs[0], ys[0], false, valueData[0]); for(i = 0; i < n - 1; i++) { path.curve( // First control point xs[i] + dxs[i] / 3, ys[i] + ms[i] * dxs[i] / 3, // Second control point xs[i + 1] - dxs[i] / 3, ys[i + 1] - ms[i + 1] * dxs[i] / 3, // End point xs[i + 1], ys[i + 1], false, valueData[i + 1] ); } return path; } }; }; /** * Step interpolation will cause the line chart to move in steps rather than diagonal or smoothed lines. This interpolation will create additional points that will also be drawn when the `showPoint` option is enabled. * * All smoothing functions within Chartist are factory functions that accept an options parameter. The step interpolation function accepts one configuration parameter `postpone`, that can be `true` or `false`. The default value is `true` and will cause the step to occur where the value actually changes. If a different behaviour is needed where the step is shifted to the left and happens before the actual value, this option can be set to `false`. * * @example * var chart = new Chartist.Line('.ct-chart', { * labels: [1, 2, 3, 4, 5], * series: [[1, 2, 8, 1, 7]] * }, { * lineSmooth: Chartist.Interpolation.step({ * postpone: true, * fillHoles: false * }) * }); * * @memberof Chartist.Interpolation * @param options * @returns {Function} */ Chartist.Interpolation.step = function(options) { var defaultOptions = { postpone: true, fillHoles: false }; options = Chartist.extend({}, defaultOptions, options); return function step(pathCoordinates, valueData) { var path = new Chartist.Svg.Path(); var prevX, prevY, prevData; for (var i = 0; i < pathCoordinates.length; i += 2) { var currX = pathCoordinates[i]; var currY = pathCoordinates[i + 1]; var currData = valueData[i / 2]; // If the current point is also not a hole we can draw the step lines if(currData.value !== undefined) { if(prevData === undefined) { path.move(currX, currY, false, currData); } else { if(options.postpone) { // If postponed we should draw the step line with the value of the previous value path.line(currX, prevY, false, prevData); } else { // If not postponed we should draw the step line with the value of the current value path.line(prevX, currY, false, currData); } // Line to the actual point (this should only be a Y-Axis movement path.line(currX, currY, false, currData); } prevX = currX; prevY = currY; prevData = currData; } else if(!options.fillHoles) { prevX = prevY = prevData = undefined; } } return path; }; }; }(window, document, Chartist)); ;/** * A very basic event module that helps to generate and catch events. * * @module Chartist.Event */ /* global Chartist */ (function (window, document, Chartist) { 'use strict'; Chartist.EventEmitter = function () { var handlers = []; /** * Add an event handler for a specific event * * @memberof Chartist.Event * @param {String} event The event name * @param {Function} handler A event handler function */ function addEventHandler(event, handler) { handlers[event] = handlers[event] || []; handlers[event].push(handler); } /** * Remove an event handler of a specific event name or remove all event handlers for a specific event. * * @memberof Chartist.Event * @param {String} event The event name where a specific or all handlers should be removed * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed. */ function removeEventHandler(event, handler) { // Only do something if there are event handlers with this name existing if(handlers[event]) { // If handler is set we will look for a specific handler and only remove this if(handler) { handlers[event].splice(handlers[event].indexOf(handler), 1); if(handlers[event].length === 0) { delete handlers[event]; } } else { // If no handler is specified we remove all handlers for this event delete handlers[event]; } } } /** * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter. * * @memberof Chartist.Event * @param {String} event The event name that should be triggered * @param {*} data Arbitrary data that will be passed to the event handler callback functions */ function emit(event, data) { // Only do something if there are event handlers with this name existing if(handlers[event]) { handlers[event].forEach(function(handler) { handler(data); }); } // Emit event to star event handlers if(handlers['*']) { handlers['*'].forEach(function(starHandler) { starHandler(event, data); }); } } return { addEventHandler: addEventHandler, removeEventHandler: removeEventHandler, emit: emit }; }; }(window, document, Chartist)); ;/** * This module provides some basic prototype inheritance utilities. * * @module Chartist.Class */ /* global Chartist */ (function(window, document, Chartist) { 'use strict'; function listToArray(list) { var arr = []; if (list.length) { for (var i = 0; i < list.length; i++) { arr.push(list[i]); } } return arr; } /** * Method to extend from current prototype. * * @memberof Chartist.Class * @param {Object} properties The object that serves as definition for the prototype that gets created for the new class. This object should always contain a constructor property that is the desired constructor for the newly created class. * @param {Object} [superProtoOverride] By default extens will use the current class prototype or Chartist.class. With this parameter you can specify any super prototype that will be used. * @return {Function} Constructor function of the new class * * @example * var Fruit = Class.extend({ * color: undefined, * sugar: undefined, * * constructor: function(color, sugar) { * this.color = color; * this.sugar = sugar; * }, * * eat: function() { * this.sugar = 0; * return this; * } * }); * * var Banana = Fruit.extend({ * length: undefined, * * constructor: function(length, sugar) { * Banana.super.constructor.call(this, 'Yellow', sugar); * this.length = length; * } * }); * * var banana = new Banana(20, 40); * console.log('banana instanceof Fruit', banana instanceof Fruit); * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana)); * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype); * console.log(banana.sugar); * console.log(banana.eat().sugar); * console.log(banana.color); */ function extend(properties, superProtoOverride) { var superProto = superProtoOverride || this.prototype || Chartist.Class; var proto = Object.create(superProto); Chartist.Class.cloneDefinitions(proto, properties); var constr = function() { var fn = proto.constructor || function () {}, instance; // If this is linked to the Chartist namespace the constructor was not called with new // To provide a fallback we will instantiate here and return the instance instance = this === Chartist ? Object.create(proto) : this; fn.apply(instance, Array.prototype.slice.call(arguments, 0)); // If this constructor was not called with new we need to return the instance // This will not harm when the constructor has been called with new as the returned value is ignored return instance; }; constr.prototype = proto; constr.super = superProto; constr.extend = this.extend; return constr; } // Variable argument list clones args > 0 into args[0] and retruns modified args[0] function cloneDefinitions() { var args = listToArray(arguments); var target = args[0]; args.splice(1, args.length - 1).forEach(function (source) { Object.getOwnPropertyNames(source).forEach(function (propName) { // If this property already exist in target we delete it first delete target[propName]; // Define the property with the descriptor from source Object.defineProperty(target, propName, Object.getOwnPropertyDescriptor(source, propName)); }); }); return target; } Chartist.Class = { extend: extend, cloneDefinitions: cloneDefinitions }; }(window, document, Chartist)); ;/** * Base for all chart types. The methods in Chartist.Base are inherited to all chart types. * * @module Chartist.Base */ /* global Chartist */ (function(window, document, Chartist) { 'use strict'; // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance. // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage. // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj // The problem is with the label offsets that can't be converted into percentage and affecting the chart container /** * Updates the chart which currently does a full reconstruction of the SVG DOM * * @param {Object} [data] Optional data you'd like to set for the chart before it will update. If not specified the update method will use the data that is already configured with the chart. * @param {Object} [options] Optional options you'd like to add to the previous options for the chart before it will update. If not specified the update method will use the options that have been already configured with the chart. * @param {Boolean} [override] If set to true, the passed options will be used to extend the options that have been configured already. Otherwise the chart default options will be used as the base * @memberof Chartist.Base */ function update(data, options, override) { if(data) { this.data = data || {}; this.data.labels = this.data.labels || []; this.data.series = this.data.series || []; // Event for data transformation that allows to manipulate the data before it gets rendered in the charts this.eventEmitter.emit('data', { type: 'update', data: this.data }); } if(options) { this.options = Chartist.extend({}, override ? this.options : this.defaultOptions, options); // If chartist was not initialized yet, we just set the options and leave the rest to the initialization // Otherwise we re-create the optionsProvider at this point if(!this.initializeTimeoutId) { this.optionsProvider.removeMediaQueryListeners(); this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); } } // Only re-created the chart if it has been initialized yet if(!this.initializeTimeoutId) { this.createChart(this.optionsProvider.getCurrentOptions()); } // Return a reference to the chart object to chain up calls return this; } /** * This method can be called on the API object of each chart and will un-register all event listeners that were added to other components. This currently includes a window.resize listener as well as media query listeners if any responsive options have been provided. Use this function if you need to destroy and recreate Chartist charts dynamically. * * @memberof Chartist.Base */ function detach() { // Only detach if initialization already occurred on this chart. If this chart still hasn't initialized (therefore // the initializationTimeoutId is still a valid timeout reference, we will clear the timeout if(!this.initializeTimeoutId) { window.removeEventListener('resize', this.resizeListener); this.optionsProvider.removeMediaQueryListeners(); } else { window.clearTimeout(this.initializeTimeoutId); } return this; } /** * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop. * * @memberof Chartist.Base * @param {String} event Name of the event. Check the examples for supported events. * @param {Function} handler The handler function that will be called when an event with the given name was emitted. This function will receive a data argument which contains event data. See the example for more details. */ function on(event, handler) { this.eventEmitter.addEventHandler(event, handler); return this; } /** * Use this function to un-register event handlers. If the handler function parameter is omitted all handlers for the given event will be un-registered. * * @memberof Chartist.Base * @param {String} event Name of the event for which a handler should be removed * @param {Function} [handler] The handler function that that was previously used to register a new event handler. This handler will be removed from the event handler list. If this parameter is omitted then all event handlers for the given event are removed from the list. */ function off(event, handler) { this.eventEmitter.removeEventHandler(event, handler); return this; } function initialize() { // Add window resize listener that re-creates the chart window.addEventListener('resize', this.resizeListener); // Obtain current options based on matching media queries (if responsive options are given) // This will also register a listener that is re-creating the chart based on media changes this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter); // Register options change listener that will trigger a chart update this.eventEmitter.addEventHandler('optionsChanged', function() { this.update(); }.bind(this)); // Before the first chart creation we need to register us with all plugins that are configured // Initialize all relevant plugins with our chart object and the plugin options specified in the config if(this.options.plugins) { this.options.plugins.forEach(function(plugin) { if(plugin instanceof Array) { plugin[0](this, plugin[1]); } else { plugin(this); } }.bind(this)); } // Event for data transformation that allows to manipulate the data before it gets rendered in the charts this.eventEmitter.emit('data', { type: 'initial', data: this.data }); // Create the first chart this.createChart(this.optionsProvider.getCurrentOptions()); // As chart is initialized from the event loop now we can reset our timeout reference // This is important if the chart gets initialized on the same element twice this.initializeTimeoutId = undefined; } /** * Constructor of chart base class. * * @param query * @param data * @param defaultOptions * @param options * @param responsiveOptions * @constructor */ function Base(query, data, defaultOptions, options, responsiveOptions) { this.container = Chartist.querySelector(query); this.data = data || {}; this.data.labels = this.data.labels || []; this.data.series = this.data.series || []; this.defaultOptions = defaultOptions; this.options = options; this.responsiveOptions = responsiveOptions; this.eventEmitter = Chartist.EventEmitter(); this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility'); this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute'); this.resizeListener = function resizeListener(){ this.update(); }.bind(this); if(this.container) { // If chartist was already initialized in this container we are detaching all event listeners first if(this.container.__chartist__) { this.container.__chartist__.detach(); } this.container.__chartist__ = this; } // Using event loop for first draw to make it possible to register event listeners in the same call stack where // the chart was created. this.initializeTimeoutId = setTimeout(initialize.bind(this), 0); } // Creating the chart base class Chartist.Base = Chartist.Class.extend({ constructor: Base, optionsProvider: undefined, container: undefined, svg: undefined, eventEmitter: undefined, createChart: function() { throw new Error('Base chart type can\'t be instantiated!'); }, update: update, detach: detach, on: on, off: off, version: Chartist.version, supportsForeignObject: false }); }(window, document, Chartist)); ;/** * Chartist SVG module for simple SVG DOM abstraction * * @module Chartist.Svg */ /* global Chartist */ (function(window, document, Chartist) { 'use strict'; /** * Chartist.Svg creates a new SVG object wrapper with a starting element. You can use the wrapper to fluently create sub-elements and modify them. * * @memberof Chartist.Svg * @constructor * @param {String|Element} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg * @param {Object} attributes An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added. * @param {String} className This class or class list will be added to the SVG element * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child * @param {Boolean} insertFirst If this param is set to true in conjunction with a parent element the newly created element will be added as first child element in the parent element */ function Svg(name, attributes, className, parent, insertFirst) { // If Svg is getting called with an SVG element we just return the wrapper if(name instanceof Element) { this._node = name; } else { this._node = document.createElementNS(Chartist.namespaces.svg, name); // If this is an SVG element created then custom namespace if(name === 'svg') { this.attr({ 'xmlns:ct': Chartist.namespaces.ct }); } } if(attributes) { this.attr(attributes); } if(className) { this.addClass(className); } if(parent) { if (insertFirst && parent._node.firstChild) { parent._node.insertBefore(this._node, parent._node.firstChild); } else { parent._node.appendChild(this._node); } } } /** * Set attributes on the current SVG element of the wrapper you're currently working on. * * @memberof Chartist.Svg * @param {Object|String} attributes An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added. If this parameter is a String then the function is used as a getter and will return the attribute value. * @param {String} [ns] If specified, the attribute will be obtained using getAttributeNs. In order to write namepsaced attributes you can use the namespace:attribute notation within the attributes object. * @return {Object|String} The current wrapper object will be returned so it can be used for chaining or the attribute value if used as getter function. */ function attr(attributes, ns) { if(typeof attributes === 'string') { if(ns) { return this._node.getAttributeNS(ns, attributes); } else { return this._node.getAttribute(attributes); } } Object.keys(attributes).forEach(function(key) { // If the attribute value is undefined we can skip this one if(attributes[key] === undefined) { return; } if (key.indexOf(':') !== -1) { var namespacedAttribute = key.split(':'); this._node.setAttributeNS(Chartist.namespaces[namespacedAttribute[0]], key, attributes[key]); } else { this._node.setAttribute(key, attributes[key]); } }.bind(this)); return this; } /** * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily. * * @memberof Chartist.Svg * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper * @param {Object} [attributes] An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added. * @param {String} [className] This class or class list will be added to the SVG element * @param {Boolean} [insertFirst] If this param is set to true in conjunction with a parent element the newly created element will be added as first child element in the parent element * @return {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data */ function elem(name, attributes, className, insertFirst) { return new Chartist.Svg(name, attributes, className, this, insertFirst); } /** * Returns the parent Chartist.SVG wrapper object * * @memberof Chartist.Svg * @return {Chartist.Svg} Returns a Chartist.Svg wrapper around the parent node of the current node. If the parent node is not existing or it's not an SVG node then this function will return null. */ function parent() { return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null; } /** * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree. * * @memberof Chartist.Svg * @return {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element */ function root() { var node = this._node; while(node.nodeName !== 'svg') { node = node.parentNode; } return new Chartist.Svg(node); } /** * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper. * * @memberof Chartist.Svg * @param {String} selector A CSS selector that is used to query for child SVG elements * @return {Chartist.Svg} The SVG wrapper for the element found or null if no element was found */ function querySelector(selector) { var foundNode = this._node.querySelector(selector); return foundNode ? new Chartist.Svg(foundNode) : null; } /** * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper. * * @memberof Chartist.Svg * @param {String} selector A CSS selector that is used to query for child SVG elements * @return {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found */ function querySelectorAll(selector) { var foundNodes = this._node.querySelectorAll(selector); return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null; } /** * Returns the underlying SVG node for the current element. * * @memberof Chartist.Svg * @returns {Node} */ function getNode() { return this._node; } /** * This method creates a foreignObject (see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject) that allows to embed HTML content into a SVG graphic. With the help of foreignObjects you can enable the usage of regular HTML elements inside of SVG where they are subject for SVG positioning and transformation but the Browser will use the HTML rendering capabilities for the containing DOM. * * @memberof Chartist.Svg * @param {Node|String} content The DOM Node, or HTML string that will be converted to a DOM Node, that is then placed into and wrapped by the foreignObject * @param {String} [attributes] An object with properties that will be added as attributes to the foreignObject element that is created. Attributes with undefined values will not be added. * @param {String} [className] This class or class list will be added to the SVG element * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child * @return {Chartist.Svg} New wrapper object that wraps the foreignObject element */ function foreignObject(content, attributes, className, insertFirst) { // If content is string then we convert it to DOM // TODO: Handle case where content is not a string nor a DOM Node if(typeof content === 'string') { var container = document.createElement('div'); container.innerHTML = content; content = container.firstChild; } // Adding namespace to content element content.setAttribute('xmlns', Chartist.namespaces.xmlns); // Creating the foreignObject without required extension attribute (as described here // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement) var fnObj = this.elem('foreignObject', attributes, className, insertFirst); // Add content to foreignObjectElement fnObj._node.appendChild(content); return fnObj; } /** * This method adds a new text element to the current Chartist.Svg wrapper. * * @memberof Chartist.Svg * @param {String} t The text that should be added to the text element that is created * @return {Chartist.Svg} The same wrapper object that was used to add the newly created element */ function text(t) { this._node.appendChild(document.createTextNode(t)); return this; } /** * This method will clear all child nodes of the current wrapper object. * * @memberof Chartist.Svg * @return {Chartist.Svg} The same wrapper object that got emptied */ function empty() { while (this._node.firstChild) { this._node.removeChild(this._node.firstChild); } return this; } /** * This method will cause the current wrapper to remove itself from its parent wrapper. Use this method if you'd like to get rid of an element in a given DOM structure. * * @memberof Chartist.Svg * @return {Chartist.Svg} The parent wrapper object of the element that got removed */ function remove() { this._node.parentNode.removeChild(this._node); return this.parent(); } /** * This method will replace the element with a new element that can be created outside of the current DOM. * * @memberof Chartist.Svg * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object * @return {Chartist.Svg} The wrapper of the new element */ function replace(newElement) { this._node.parentNode.replaceChild(newElement._node, this._node); return newElement; } /** * This method will append an element to the current element as a child. * * @memberof Chartist.Svg * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child * @return {Chartist.Svg} The wrapper of the appended object */ function append(element, insertFirst) { if(insertFirst && this._node.firstChild) { this._node.insertBefore(element._node, this._node.firstChild); } else { this._node.appendChild(element._node); } return this; } /** * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further. * * @memberof Chartist.Svg * @return {Array} A list of classes or an empty array if there are no classes on the current element */ function classes() { return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : []; } /** * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once. * * @memberof Chartist.Svg * @param {String} names A white space separated list of class names * @return {Chartist.Svg} The wrapper of the current element */ function addClass(names) { this._node.setAttribute('class', this.classes(this._node) .concat(names.trim().split(/\s+/)) .filter(function(elem, pos, self) { return self.indexOf(elem) === pos; }).join(' ') ); return this; } /** * Removes one or a space separated list of classes from the current element. * * @memberof Chartist.Svg * @param {String} names A white space separated list of class names * @return {Chartist.Svg} The wrapper of the current element */ function removeClass(names) { var removedClasses = names.trim().split(/\s+/); this._node.setAttribute('class', this.classes(this._node).filter(function(name) { return removedClasses.indexOf(name) === -1; }).join(' ')); return this; } /** * Removes all classes from the current element. * * @memberof Chartist.Svg * @return {Chartist.Svg} The wrapper of the current element */ function removeAllClasses() { this._node.setAttribute('class', ''); return this; } /** * Get element height using `getBoundingClientRect` * * @memberof Chartist.Svg * @return {Number} The elements height in pixels */ function height() { return this._node.getBoundingClientRect().height; } /** * Get element width using `getBoundingClientRect` * * @memberof Chartist.Core * @return {Number} The elements width in pixels */ function width() { return this._node.getBoundingClientRect().width; } /** * The animate function lets you animate the current element with SMIL animations. You can add animations for multiple attributes at the same time by using an animation definition object. This object should contain SMIL animation attributes. Please refer to http://www.w3.org/TR/SVG/animate.html for a detailed specification about the available animation attributes. Additionally an easing property can be passed in the animation definition object. This can be a string with a name of an easing function in `Chartist.Svg.Easing` or an array with four numbers specifying a cubic Bézier curve. * **An animations object could look like this:** * ```javascript * element.animate({ * opacity: { * dur: 1000, * from: 0, * to: 1 * }, * x1: { * dur: '1000ms', * from: 100, * to: 200, * easing: 'easeOutQuart' * }, * y1: { * dur: '2s', * from: 0, * to: 100 * } * }); * ``` * **Automatic unit conversion** * For the `dur` and the `begin` animate attribute you can also omit a unit by passing a number. The number will automatically be converted to milli seconds. * **Guided mode** * The default behavior of SMIL animations with offset using the `begin` attribute is that the attribute will keep it's original value until the animation starts. Mostly this behavior is not desired as you'd like to have your element attributes already initialized with the animation `from` value even before the animation starts. Also if you don't specify `fill="freeze"` on an animate element or if you delete the animation after it's done (which is done in guided mode) the attribute will switch back to the initial value. This behavior is also not desired when performing simple one-time animations. For one-time animations you'd want to trigger animations immediately instead of relative to the document begin time. That's why in guided mode Chartist.Svg will also use the `begin` property to schedule a timeout and manually start the animation after the timeout. If you're using multiple SMIL definition objects for an attribute (in an array), guided mode will be disabled for this attribute, even if you explicitly enabled it. * If guided mode is enabled the following behavior is added: * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation) * - The animate element will be forced to use `fill="freeze"` * - The animation will be triggered with `beginElement()` in a timeout where `begin` of the definition object is interpreted in milli seconds. If no `begin` was specified the timeout is triggered immediately. * - After the animation the element attribute value will be set to the `to` value of the animation * - The animate element is deleted from the DOM * * @memberof Chartist.Svg * @param {Object} animations An animations object where the property keys are the attributes you'd like to animate. The properties should be objects again that contain the SMIL animation attributes (usually begin, dur, from, and to). The property begin and dur is auto converted (see Automatic unit conversion). You can also schedule multiple animations for the same attribute by passing an Array of SMIL definition objects. Attributes that contain an array of SMIL definition objects will not be executed in guided mode. * @param {Boolean} guided Specify if guided mode should be activated for this animation (see Guided mode). If not otherwise specified, guided mode will be activated. * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends. * @return {Chartist.Svg} The current element where the animation was added */ function animate(animations, guided, eventEmitter) { if(guided === undefined) { guided = true; } Object.keys(animations).forEach(function createAnimateForAttributes(attribute) { function createAnimate(animationDefinition, guided) { var attributeProperties = {}, animate, timeout, easing; // Check if an easing is specified in the definition object and delete it from the object as it will not // be part of the animate element attributes. if(animationDefinition.easing) { // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object easing = animationDefinition.easing instanceof Array ? animationDefinition.easing : Chartist.Svg.Easing[animationDefinition.easing]; delete animationDefinition.easing; } // If numeric dur or begin was provided we assume milli seconds animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms'); animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms'); if(easing) { animationDefinition.calcMode = 'spline'; animationDefinition.keySplines = easing.join(' '); animationDefinition.keyTimes = '0;1'; } // Adding "fill: freeze" if we are in guided mode and set initial attribute values if(guided) { animationDefinition.fill = 'freeze'; // Animated property on our element should already be set to the animation from value in guided mode attributeProperties[attribute] = animationDefinition.from; this.attr(attributeProperties); // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin // which needs to be in ms aside timeout = Chartist.quantity(animationDefinition.begin || 0).value; animationDefinition.begin = 'indefinite'; } animate = this.elem('animate', Chartist.extend({ attributeName: attribute }, animationDefinition)); if(guided) { // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout setTimeout(function() { // If beginElement fails we set the animated attribute to the end position and remove the animate element // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in // the browser. (Currently FF 34 does not support animate elements in foreignObjects) try { animate._node.beginElement(); } catch(err) { // Set animated attribute to current animated value attributeProperties[attribute] = animationDefinition.to; this.attr(attributeProperties); // Remove the animate element as it's no longer required animate.remove(); } }.bind(this), timeout); } if(eventEmitter) { animate._node.addEventListener('beginEvent', function handleBeginEvent() { eventEmitter.emit('animationBegin', { element: this, animate: animate._node, params: animationDefinition }); }.bind(this)); } animate._node.addEventListener('endEvent', function handleEndEvent() { if(eventEmitter) { eventEmitter.emit('animationEnd', { element: this, animate: animate._node, params: animationDefinition }); } if(guided) { // Set animated attribute to current animated value attributeProperties[attribute] = animationDefinition.to; this.attr(attributeProperties); // Remove the animate element as it's no longer required animate.remove(); } }.bind(this)); } // If current attribute is an array of definition objects we create an animate for each and disable guided mode if(animations[attribute] instanceof Array) { animations[attribute].forEach(function(animationDefinition) { createAnimate.bind(this)(animationDefinition, false); }.bind(this)); } else { createAnimate.bind(this)(animations[attribute], guided); } }.bind(this)); return this; } Chartist.Svg = Chartist.Class.extend({ constructor: Svg, attr: attr, elem: elem, parent: parent, root: root, querySelector: querySelector, querySelectorAll: querySelectorAll, getNode: getNode, foreignObject: foreignObject, text: text, empty: empty, remove: remove, replace: replace, append: append, classes: classes, addClass: addClass, removeClass: removeClass, removeAllClasses: removeAllClasses, height: height, width: width, animate: animate }); /** * This method checks for support of a given SVG feature like Extensibility, SVG-animation or the like. Check http://www.w3.org/TR/SVG11/feature for a detailed list. * * @memberof Chartist.Svg * @param {String} feature The SVG 1.1 feature that should be checked for support. * @return {Boolean} True of false if the feature is supported or not */ Chartist.Svg.isSupported = function(feature) { return document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#' + feature, '1.1'); }; /** * This Object contains some standard easing cubic bezier curves. Then can be used with their name in the `Chartist.Svg.animate`. You can also extend the list and use your own name in the `animate` function. Click the show code button to see the available bezier functions. * * @memberof Chartist.Svg */ var easingCubicBeziers = { easeInSine: [0.47, 0, 0.745, 0.715], easeOutSine: [0.39, 0.575, 0.565, 1], easeInOutSine: [0.445, 0.05, 0.55, 0.95], easeInQuad: [0.55, 0.085, 0.68, 0.53], easeOutQuad: [0.25, 0.46, 0.45, 0.94], easeInOutQuad: [0.455, 0.03, 0.515, 0.955], easeInCubic: [0.55, 0.055, 0.675, 0.19], easeOutCubic: [0.215, 0.61, 0.355, 1], easeInOutCubic: [0.645, 0.045, 0.355, 1], easeInQuart: [0.895, 0.03, 0.685, 0.22], easeOutQuart: [0.165, 0.84, 0.44, 1], easeInOutQuart: [0.77, 0, 0.175, 1], easeInQuint: [0.755, 0.05, 0.855, 0.06], easeOutQuint: [0.23, 1, 0.32, 1], easeInOutQuint: [0.86, 0, 0.07, 1], easeInExpo: [0.95, 0.05, 0.795, 0.035], easeOutExpo: [0.19, 1, 0.22, 1], easeInOutExpo: [1, 0, 0, 1], easeInCirc: [0.6, 0.04, 0.98, 0.335], easeOutCirc: [0.075, 0.82, 0.165, 1], easeInOutCirc: [0.785, 0.135, 0.15, 0.86], easeInBack: [0.6, -0.28, 0.735, 0.045], easeOutBack: [0.175, 0.885, 0.32, 1.275], easeInOutBack: [0.68, -0.55, 0.265, 1.55] }; Chartist.Svg.Easing = easingCubicBeziers; /** * This helper class is to wrap multiple `Chartist.Svg` elements into a list where you can call the `Chartist.Svg` functions on all elements in the list with one call. This is helpful when you'd like to perform calls with `Chartist.Svg` on multiple elements. * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`. * * @memberof Chartist.Svg * @param {Array|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll) * @constructor */ function SvgList(nodeList) { var list = this; this.svgElements = []; for(var i = 0; i < nodeList.length; i++) { this.svgElements.push(new Chartist.Svg(nodeList[i])); } // Add delegation methods for Chartist.Svg Object.keys(Chartist.Svg.prototype).filter(function(prototypeProperty) { return ['constructor', 'parent', 'querySelector', 'querySelectorAll', 'replace', 'append', 'classes', 'height', 'width'].indexOf(prototypeProperty) === -1; }).forEach(function(prototypeProperty) { list[prototypeProperty] = function() { var args = Array.prototype.slice.call(arguments, 0); list.svgElements.forEach(function(element) { Chartist.Svg.prototype[prototypeProperty].apply(element, args); }); return list; }; }); } Chartist.Svg.List = Chartist.Class.extend({ constructor: SvgList }); }(window, document, Chartist)); ;/** * Chartist SVG path module for SVG path description creation and modification. * * @module Chartist.Svg.Path */ /* global Chartist */ (function(window, document, Chartist) { 'use strict'; /** * Contains the descriptors of supported element types in a SVG path. Currently only move, line and curve are supported. * * @memberof Chartist.Svg.Path * @type {Object} */ var elementDescriptions = { m: ['x', 'y'], l: ['x', 'y'], c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'], a: ['rx', 'ry', 'xAr', 'lAf', 'sf', 'x', 'y'] }; /** * Default options for newly created SVG path objects. * * @memberof Chartist.Svg.Path * @type {Object} */ var defaultOptions = { // The accuracy in digit count after the decimal point. This will be used to round numbers in the SVG path. If this option is set to false then no rounding will be performed. accuracy: 3 }; function element(command, params, pathElements, pos, relative, data) { var pathElement = Chartist.extend({ command: relative ? command.toLowerCase() : command.toUpperCase() }, params, data ? { data: data } : {} ); pathElements.splice(pos, 0, pathElement); } function forEachParam(pathElements, cb) { pathElements.forEach(function(pathElement, pathElementIndex) { elementDescriptions[pathElement.command.toLowerCase()].forEach(function(paramName, paramIndex) { cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements); }); }); } /** * Used to construct a new path object. * * @memberof Chartist.Svg.Path * @param {Boolean} close If set to true then this path will be closed when stringified (with a Z at the end) * @param {Object} options Options object that overrides the default objects. See default options for more details. * @constructor */ function SvgPath(close, options) { this.pathElements = []; this.pos = 0; this.close = close; this.options = Chartist.extend({}, defaultOptions, options); } /** * Gets or sets the current position (cursor) inside of the path. You can move around the cursor freely but limited to 0 or the count of existing elements. All modifications with element functions will insert new elements at the position of this cursor. * * @memberof Chartist.Svg.Path * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array. * @return {Chartist.Svg.Path|Number} If the position parameter was passed then the return value will be the path object for easy call chaining. If no position parameter was passed then the current position is returned. */ function position(pos) { if(pos !== undefined) { this.pos = Math.max(0, Math.min(this.pathElements.length, pos)); return this; } else { return this.pos; } } /** * Removes elements from the path starting at the current position. * * @memberof Chartist.Svg.Path * @param {Number} count Number of path elements that should be removed from the current position. * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function remove(count) { this.pathElements.splice(this.pos, count); return this; } /** * Use this function to add a new move SVG path element. * * @memberof Chartist.Svg.Path * @param {Number} x The x coordinate for the move element. * @param {Number} y The y coordinate for the move element. * @param {Boolean} [relative] If set to true the move element will be created with relative coordinates (lowercase letter) * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function move(x, y, relative, data) { element('M', { x: +x, y: +y }, this.pathElements, this.pos++, relative, data); return this; } /** * Use this function to add a new line SVG path element. * * @memberof Chartist.Svg.Path * @param {Number} x The x coordinate for the line element. * @param {Number} y The y coordinate for the line element. * @param {Boolean} [relative] If set to true the line element will be created with relative coordinates (lowercase letter) * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function line(x, y, relative, data) { element('L', { x: +x, y: +y }, this.pathElements, this.pos++, relative, data); return this; } /** * Use this function to add a new curve SVG path element. * * @memberof Chartist.Svg.Path * @param {Number} x1 The x coordinate for the first control point of the bezier curve. * @param {Number} y1 The y coordinate for the first control point of the bezier curve. * @param {Number} x2 The x coordinate for the second control point of the bezier curve. * @param {Number} y2 The y coordinate for the second control point of the bezier curve. * @param {Number} x The x coordinate for the target point of the curve element. * @param {Number} y The y coordinate for the target point of the curve element. * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function curve(x1, y1, x2, y2, x, y, relative, data) { element('C', { x1: +x1, y1: +y1, x2: +x2, y2: +y2, x: +x, y: +y }, this.pathElements, this.pos++, relative, data); return this; } /** * Use this function to add a new non-bezier curve SVG path element. * * @memberof Chartist.Svg.Path * @param {Number} rx The radius to be used for the x-axis of the arc. * @param {Number} ry The radius to be used for the y-axis of the arc. * @param {Number} xAr Defines the orientation of the arc * @param {Number} lAf Large arc flag * @param {Number} sf Sweep flag * @param {Number} x The x coordinate for the target point of the curve element. * @param {Number} y The y coordinate for the target point of the curve element. * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter) * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function arc(rx, ry, xAr, lAf, sf, x, y, relative, data) { element('A', { rx: +rx, ry: +ry, xAr: +xAr, lAf: +lAf, sf: +sf, x: +x, y: +y }, this.pathElements, this.pos++, relative, data); return this; } /** * Parses an SVG path seen in the d attribute of path elements, and inserts the parsed elements into the existing path object at the current cursor position. Any closing path indicators (Z at the end of the path) will be ignored by the parser as this is provided by the close option in the options of the path object. * * @memberof Chartist.Svg.Path * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components. * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function parse(path) { // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']] var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2') .replace(/([0-9])([A-Za-z])/g, '$1 $2') .split(/[\s,]+/) .reduce(function(result, element) { if(element.match(/[A-Za-z]/)) { result.push([]); } result[result.length - 1].push(element); return result; }, []); // If this is a closed path we remove the Z at the end because this is determined by the close option if(chunks[chunks.length - 1][0].toUpperCase() === 'Z') { chunks.pop(); } // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters // For example {command: 'M', x: '10', y: '10'} var elements = chunks.map(function(chunk) { var command = chunk.shift(), description = elementDescriptions[command.toLowerCase()]; return Chartist.extend({ command: command }, description.reduce(function(result, paramName, index) { result[paramName] = +chunk[index]; return result; }, {})); }); // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position var spliceArgs = [this.pos, 0]; Array.prototype.push.apply(spliceArgs, elements); Array.prototype.splice.apply(this.pathElements, spliceArgs); // Increase the internal position by the element count this.pos += elements.length; return this; } /** * This function renders to current SVG path object into a final SVG string that can be used in the d attribute of SVG path elements. It uses the accuracy option to round big decimals. If the close parameter was set in the constructor of this path object then a path closing Z will be appended to the output string. * * @memberof Chartist.Svg.Path * @return {String} */ function stringify() { var accuracyMultiplier = Math.pow(10, this.options.accuracy); return this.pathElements.reduce(function(path, pathElement) { var params = elementDescriptions[pathElement.command.toLowerCase()].map(function(paramName) { return this.options.accuracy ? (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) : pathElement[paramName]; }.bind(this)); return path + pathElement.command + params.join(','); }.bind(this), '') + (this.close ? 'Z' : ''); } /** * Scales all elements in the current SVG path object. There is an individual parameter for each coordinate. Scaling will also be done for control points of curves, affecting the given coordinate. * * @memberof Chartist.Svg.Path * @param {Number} x The number which will be used to scale the x, x1 and x2 of all path elements. * @param {Number} y The number which will be used to scale the y, y1 and y2 of all path elements. * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function scale(x, y) { forEachParam(this.pathElements, function(pathElement, paramName) { pathElement[paramName] *= paramName[0] === 'x' ? x : y; }); return this; } /** * Translates all elements in the current SVG path object. The translation is relative and there is an individual parameter for each coordinate. Translation will also be done for control points of curves, affecting the given coordinate. * * @memberof Chartist.Svg.Path * @param {Number} x The number which will be used to translate the x, x1 and x2 of all path elements. * @param {Number} y The number which will be used to translate the y, y1 and y2 of all path elements. * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function translate(x, y) { forEachParam(this.pathElements, function(pathElement, paramName) { pathElement[paramName] += paramName[0] === 'x' ? x : y; }); return this; } /** * This function will run over all existing path elements and then loop over their attributes. The callback function will be called for every path element attribute that exists in the current path. * The method signature of the callback function looks like this: * ```javascript * function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) * ``` * If something else than undefined is returned by the callback function, this value will be used to replace the old value. This allows you to build custom transformations of path objects that can't be achieved using the basic transformation functions scale and translate. * * @memberof Chartist.Svg.Path * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description. * @return {Chartist.Svg.Path} The current path object for easy call chaining. */ function transform(transformFnc) { forEachParam(this.pathElements, function(pathElement, paramName, pathElementIndex, paramIndex, pathElements) { var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements); if(transformed || transformed === 0) { pathElement[paramName] = transformed; } }); return this; } /** * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned. * * @memberof Chartist.Svg.Path * @param {Boolean} [close] Optional option to set the new cloned path to closed. If not specified or false, the original path close option will be used. * @return {Chartist.Svg.Path} */ function clone(close) { var c = new Chartist.Svg.Path(close || this.close); c.pos = this.pos; c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) { return Chartist.extend({}, pathElement); }); c.options = Chartist.extend({}, this.options); return c; } /** * Split a Svg.Path object by a specific command in the path chain. The path chain will be split and an array of newly created paths objects will be returned. This is useful if you'd like to split an SVG path by it's move commands, for example, in order to isolate chunks of drawings. * * @memberof Chartist.Svg.Path * @param {String} command The command you'd like to use to split the path * @return {Array} */ function splitByCommand(command) { var split = [ new Chartist.Svg.Path() ]; this.pathElements.forEach(function(pathElement) { if(pathElement.command === command.toUpperCase() && split[split.length - 1].pathElements.length !== 0) { split.push(new Chartist.Svg.Path()); } split[split.length - 1].pathElements.push(pathElement); }); return split; } /** * This static function on `Chartist.Svg.Path` is joining multiple paths together into one paths. * * @memberof Chartist.Svg.Path * @param {Array} paths A list of paths to be joined together. The order is important. * @param {boolean} close If the newly created path should be a closed path * @param {Object} options Path options for the newly created path. * @return {Chartist.Svg.Path} */ function join(paths, close, options) { var joinedPath = new Chartist.Svg.Path(close, options); for(var i = 0; i < paths.length; i++) { var path = paths[i]; for(var j = 0; j < path.pathElements.length; j++) { joinedPath.pathElements.push(path.pathElements[j]); } } return joinedPath; } Chartist.Svg.Path = Chartist.Class.extend({ constructor: SvgPath, position: position, remove: remove, move: move, line: line, curve: curve, arc: arc, scale: scale, translate: translate, transform: transform, parse: parse, stringify: stringify, clone: clone, splitByCommand: splitByCommand }); Chartist.Svg.Path.elementDescriptions = elementDescriptions; Chartist.Svg.Path.join = join; }(window, document, Chartist)); ;/* global Chartist */ (function (window, document, Chartist) { 'use strict'; var axisUnits = { x: { pos: 'x', len: 'width', dir: 'horizontal', rectStart: 'x1', rectEnd: 'x2', rectOffset: 'y2' }, y: { pos: 'y', len: 'height', dir: 'vertical', rectStart: 'y2', rectEnd: 'y1', rectOffset: 'x1' } }; function Axis(units, chartRect, ticks, options) { this.units = units; this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x; this.chartRect = chartRect; this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart]; this.gridOffset = chartRect[units.rectOffset]; this.ticks = ticks; this.options = options; } function createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) { var axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()]; var projectedValues = this.ticks.map(this.projectValue.bind(this)); var labelValues = this.ticks.map(axisOptions.labelInterpolationFnc); projectedValues.forEach(function(projectedValue, index) { var labelOffset = { x: 0, y: 0 }; // TODO: Find better solution for solving this problem // Calculate how much space we have available for the label var labelLength; if(projectedValues[index + 1]) { // If we still have one label ahead, we can calculate the distance to the next tick / label labelLength = projectedValues[index + 1] - projectedValue; } else { // If we don't have a label ahead and we have only two labels in total, we just take the remaining distance to // on the whole axis length. We limit that to a minimum of 30 pixel, so that labels close to the border will // still be visible inside of the chart padding. labelLength = Math.max(this.axisLength - projectedValue, 30); } // Skip grid lines and labels where interpolated label values are falsey (execpt for 0) if(Chartist.isFalseyButZero(labelValues[index]) && labelValues[index] !== '') { return; } // Transform to global coordinates using the chartRect // We also need to set the label offset for the createLabel function if(this.units.pos === 'x') { projectedValue = this.chartRect.x1 + projectedValue; labelOffset.x = chartOptions.axisX.labelOffset.x; // If the labels should be positioned in start position (top side for vertical axis) we need to set a // different offset as for positioned with end (bottom) if(chartOptions.axisX.position === 'start') { labelOffset.y = this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); } else { labelOffset.y = this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20); } } else { projectedValue = this.chartRect.y1 - projectedValue; labelOffset.y = chartOptions.axisY.labelOffset.y - (useForeignObject ? labelLength : 0); // If the labels should be positioned in start position (left side for horizontal axis) we need to set a // different offset as for positioned with end (right side) if(chartOptions.axisY.position === 'start') { labelOffset.x = useForeignObject ? this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : this.chartRect.x1 - 10; } else { labelOffset.x = this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10; } } if(axisOptions.showGrid) { Chartist.createGrid(projectedValue, index, this, this.gridOffset, this.chartRect[this.counterUnits.len](), gridGroup, [ chartOptions.classNames.grid, chartOptions.classNames[this.units.dir] ], eventEmitter); } if(axisOptions.showLabel) { Chartist.createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [ chartOptions.classNames.label, chartOptions.classNames[this.units.dir], (axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end']) ], useForeignObject, eventEmitter); } }.bind(this)); } Chartist.Axis = Chartist.Class.extend({ constructor: Axis, createGridAndLabels: createGridAndLabels, projectValue: function(value, index, data) { throw new Error('Base axis can\'t be instantiated!'); } }); Chartist.Axis.units = axisUnits; }(window, document, Chartist)); ;/** * The auto scale axis uses standard linear scale projection of values along an axis. It uses order of magnitude to find a scale automatically and evaluates the available space in order to find the perfect amount of ticks for your chart. * **Options** * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings. * ```javascript * var options = { * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored * high: 100, * // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored * low: 0, * // This option will be used when finding the right scale division settings. The amount of ticks on the scale will be determined so that as many ticks as possible will be displayed, while not violating this minimum required space (in pixel). * scaleMinSpace: 20, * // Can be set to true or false. If set to true, the scale will be generated with whole numbers only. * onlyInteger: true, * // The reference value can be used to make sure that this value will always be on the chart. This is especially useful on bipolar charts where the bipolar center always needs to be part of the chart. * referenceValue: 5 * }; * ``` * * @module Chartist.AutoScaleAxis */ /* global Chartist */ (function (window, document, Chartist) { 'use strict'; function AutoScaleAxis(axisUnit, data, chartRect, options) { // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos); this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger); this.range = { min: this.bounds.min, max: this.bounds.max }; Chartist.AutoScaleAxis.super.constructor.call(this, axisUnit, chartRect, this.bounds.values, options); } function projectValue(value) { return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range; } Chartist.AutoScaleAxis = Chartist.Axis.extend({ constructor: AutoScaleAxis, projectValue: projectValue }); }(window, document, Chartist)); ;/** * The fixed scale axis uses standard linear projection of values along an axis. It makes use of a divisor option to divide the range provided from the minimum and maximum value or the options high and low that will override the computed minimum and maximum. * **Options** * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings. * ```javascript * var options = { * // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored * high: 100, * // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored * low: 0, * // If specified then the value range determined from minimum to maximum (or low and high) will be divided by this number and ticks will be generated at those division points. The default divisor is 1. * divisor: 4, * // If ticks is explicitly set, then the axis will not compute the ticks with the divisor, but directly use the data in ticks to determine at what points on the axis a tick need to be generated. * ticks: [1, 10, 20, 30] * }; * ``` * * @module Chartist.FixedScaleAxis */ /* global Chartist */ (function (window, document, Chartist) { 'use strict'; function FixedScaleAxis(axisUnit, data, chartRect, options) { var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos); this.divisor = options.divisor || 1; this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) { return highLow.low + (highLow.high - highLow.low) / this.divisor * index; }.bind(this)); this.ticks.sort(function(a, b) { return a - b; }); this.range = { min: highLow.low, max: highLow.high }; Chartist.FixedScaleAxis.super.constructor.call(this, axisUnit, chartRect, this.ticks, options); this.stepLength = this.axisLength / this.divisor; } function projectValue(value) { return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min); } Chartist.FixedScaleAxis = Chartist.Axis.extend({ constructor: FixedScaleAxis, projectValue: projectValue }); }(window, document, Chartist)); ;/** * The step axis for step based charts like bar chart or step based line charts. It uses a fixed amount of ticks that will be equally distributed across the whole axis length. The projection is done using the index of the data value rather than the value itself and therefore it's only useful for distribution purpose. * **Options** * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings. * ```javascript * var options = { * // Ticks to be used to distribute across the axis length. As this axis type relies on the index of the value rather than the value, arbitrary data that can be converted to a string can be used as ticks. * ticks: ['One', 'Two', 'Three'], * // If set to true the full width will be used to distribute the values where the last value will be at the maximum of the axis length. If false the spaces between the ticks will be evenly distributed instead. * stretch: true * }; * ``` * * @module Chartist.StepAxis */ /* global Chartist */ (function (window, document, Chartist) { 'use strict'; function StepAxis(axisUnit, data, chartRect, options) { Chartist.StepAxis.super.constructor.call(this, axisUnit, chartRect, options.ticks, options); var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0)); this.stepLength = this.axisLength / calc; } function projectValue(value, index) { return this.stepLength * index; } Chartist.StepAxis = Chartist.Axis.extend({ constructor: StepAxis, projectValue: projectValue }); }(window, document, Chartist)); ;/** * The Chartist line chart can be used to draw Line or Scatter charts. If used in the browser you can access the global `Chartist` namespace where you find the `Line` function as a main entry point. * * For examples on how to use the line chart please check the examples of the `Chartist.Line` method. * * @module Chartist.Line */ /* global Chartist */ (function(window, document, Chartist){ 'use strict'; /** * Default options in line charts. Expand the code view to see a detailed list of options with comments. * * @memberof Chartist.Line */ var defaultOptions = { // Options for X-Axis axisX: { // The offset of the labels to the chart area offset: 30, // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis. position: 'end', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, // If labels should be shown or not showLabel: true, // If the axis grid should be drawn or not showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // Set the axis type to be used to project values on this axis. If not defined, Chartist.StepAxis will be used for the X-Axis, where the ticks option will be set to the labels in the data and the stretch option will be set to the global fullWidth option. This type can be changed to any axis constructor available (e.g. Chartist.FixedScaleAxis), where all axis options should be present here. type: undefined }, // Options for Y-Axis axisY: { // The offset of the labels to the chart area offset: 40, // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis. position: 'start', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, // If labels should be shown or not showLabel: true, // If the axis grid should be drawn or not showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // Set the axis type to be used to project values on this axis. If not defined, Chartist.AutoScaleAxis will be used for the Y-Axis, where the high and low options will be set to the global high and low options. This type can be changed to any axis constructor available (e.g. Chartist.FixedScaleAxis), where all axis options should be present here. type: undefined, // This value specifies the minimum height in pixel of the scale steps scaleMinSpace: 20, // Use only integer values (whole numbers) for the scale steps onlyInteger: false }, // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') height: undefined, // If the line should be drawn or not showLine: true, // If dots should be drawn or not showPoint: true, // If the line chart should draw an area showArea: false, // The base for the area chart that will be used to close the area shape (is normally 0) areaBase: 0, // Specify if the lines should be smoothed. This value can be true or false where true will result in smoothing using the default smoothing interpolation function Chartist.Interpolation.cardinal and false results in Chartist.Interpolation.none. You can also choose other smoothing / interpolation functions available in the Chartist.Interpolation module, or write your own interpolation function. Check the examples for a brief description. lineSmooth: true, // If the line chart should add a background fill to the .ct-grids group. showGridBackground: false, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5} chartPadding: { top: 15, right: 15, bottom: 5, left: 10 }, // When set to true, the last grid line on the x-axis is not drawn and the chart elements will expand to the full available width of the chart. For the last label to be drawn correctly you might need to add chart padding or offset the last label with a draw event handler. fullWidth: false, // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. reverseData: false, // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-line', label: 'ct-label', labelGroup: 'ct-labels', series: 'ct-series', line: 'ct-line', point: 'ct-point', area: 'ct-area', grid: 'ct-grid', gridGroup: 'ct-grids', gridBackground: 'ct-grid-background', vertical: 'ct-vertical', horizontal: 'ct-horizontal', start: 'ct-start', end: 'ct-end' } }; /** * Creates a new chart * */ function createChart(options) { var data = Chartist.normalizeData(this.data, options.reverseData, true); // Create new svg object this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart); // Create groups for labels, grid and series var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); var seriesGroup = this.svg.elem('g'); var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var axisX, axisY; if(options.axisX.type === undefined) { axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, { ticks: data.normalized.labels, stretch: options.fullWidth })); } else { axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX); } if(options.axisY.type === undefined) { axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, { high: Chartist.isNumeric(options.high) ? options.high : options.axisY.high, low: Chartist.isNumeric(options.low) ? options.low : options.axisY.low })); } else { axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY); } axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); if (options.showGridBackground) { Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); } // Draw the series data.raw.series.forEach(function(series, seriesIndex) { var seriesElement = seriesGroup.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ 'ct:series-name': series.name, 'ct:meta': Chartist.serialize(series.meta) }); // Use series class from series data or if not set generate one seriesElement.addClass([ options.classNames.series, (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); var pathCoordinates = [], pathData = []; data.normalized.series[seriesIndex].forEach(function(value, valueIndex) { var p = { x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized.series[seriesIndex]), y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized.series[seriesIndex]) }; pathCoordinates.push(p.x, p.y); pathData.push({ value: value, valueIndex: valueIndex, meta: Chartist.getMetaData(series, valueIndex) }); }.bind(this)); var seriesOptions = { lineSmooth: Chartist.getSeriesOption(series, options, 'lineSmooth'), showPoint: Chartist.getSeriesOption(series, options, 'showPoint'), showLine: Chartist.getSeriesOption(series, options, 'showLine'), showArea: Chartist.getSeriesOption(series, options, 'showArea'), areaBase: Chartist.getSeriesOption(series, options, 'areaBase') }; var smoothing = typeof seriesOptions.lineSmooth === 'function' ? seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.monotoneCubic() : Chartist.Interpolation.none()); // Interpolating path where pathData will be used to annotate each path element so we can trace back the original // index, value and meta data var path = smoothing(pathCoordinates, pathData); // If we should show points we need to create them now to avoid secondary loop // Points are drawn from the pathElements returned by the interpolation function // Small offset for Firefox to render squares correctly if (seriesOptions.showPoint) { path.pathElements.forEach(function(pathElement) { var point = seriesElement.elem('line', { x1: pathElement.x, y1: pathElement.y, x2: pathElement.x + 0.01, y2: pathElement.y }, options.classNames.point).attr({ 'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNumeric).join(','), 'ct:meta': Chartist.serialize(pathElement.data.meta) }); this.eventEmitter.emit('draw', { type: 'point', value: pathElement.data.value, index: pathElement.data.valueIndex, meta: pathElement.data.meta, series: series, seriesIndex: seriesIndex, axisX: axisX, axisY: axisY, group: seriesElement, element: point, x: pathElement.x, y: pathElement.y }); }.bind(this)); } if(seriesOptions.showLine) { var line = seriesElement.elem('path', { d: path.stringify() }, options.classNames.line, true); this.eventEmitter.emit('draw', { type: 'line', values: data.normalized.series[seriesIndex], path: path.clone(), chartRect: chartRect, index: seriesIndex, series: series, seriesIndex: seriesIndex, seriesMeta: series.meta, axisX: axisX, axisY: axisY, group: seriesElement, element: line }); } // Area currently only works with axes that support a range! if(seriesOptions.showArea && axisY.range) { // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that // the area is not drawn outside the chart area. var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min); // We project the areaBase value into screen coordinates var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase); // In order to form the area we'll first split the path by move commands so we can chunk it up into segments path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) { // We filter only "solid" segments that contain more than one point. Otherwise there's no need for an area return pathSegment.pathElements.length > 1; }).map(function convertToArea(solidPathSegments) { // Receiving the filtered solid path segments we can now convert those segments into fill areas var firstElement = solidPathSegments.pathElements[0]; var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1]; // Cloning the solid path segment with closing option and removing the first move command from the clone // We then insert a new move that should start at the area base and draw a straight line up or down // at the end of the path we add an additional straight line to the projected area base value // As the closing option is set our path will be automatically closed return solidPathSegments.clone(true) .position(0) .remove(1) .move(firstElement.x, areaBaseProjected) .line(firstElement.x, firstElement.y) .position(solidPathSegments.pathElements.length + 1) .line(lastElement.x, areaBaseProjected); }).forEach(function createArea(areaPath) { // For each of our newly created area paths, we'll now create path elements by stringifying our path objects // and adding the created DOM elements to the correct series group var area = seriesElement.elem('path', { d: areaPath.stringify() }, options.classNames.area, true); // Emit an event for each area that was drawn this.eventEmitter.emit('draw', { type: 'area', values: data.normalized.series[seriesIndex], path: areaPath.clone(), series: series, seriesIndex: seriesIndex, axisX: axisX, axisY: axisY, chartRect: chartRect, index: seriesIndex, group: seriesElement, element: area }); }.bind(this)); } }.bind(this)); this.eventEmitter.emit('created', { bounds: axisY.bounds, chartRect: chartRect, axisX: axisX, axisY: axisY, svg: this.svg, options: options }); } /** * This method creates a new line chart. * * @memberof Chartist.Line * @param {String|Node} query A selector query string or directly a DOM element * @param {Object} data The data object that needs to consist of a labels and a series array * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] * @return {Object} An object which exposes the API for the created chart * * @example * // Create a simple line chart * var data = { * // A labels array that can contain any sort of values * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], * // Our series array that contains series objects or in this case series data arrays * series: [ * [5, 2, 4, 2, 0] * ] * }; * * // As options we currently only set a static size of 300x200 px * var options = { * width: '300px', * height: '200px' * }; * * // In the global name space Chartist we call the Line function to initialize a line chart. As a first parameter we pass in a selector where we would like to get our chart created. Second parameter is the actual data object and as a third parameter we pass in our options * new Chartist.Line('.ct-chart', data, options); * * @example * // Use specific interpolation function with configuration from the Chartist.Interpolation module * * var chart = new Chartist.Line('.ct-chart', { * labels: [1, 2, 3, 4, 5], * series: [ * [1, 1, 8, 1, 7] * ] * }, { * lineSmooth: Chartist.Interpolation.cardinal({ * tension: 0.2 * }) * }); * * @example * // Create a line chart with responsive options * * var data = { * // A labels array that can contain any sort of values * labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], * // Our series array that contains series objects or in this case series data arrays * series: [ * [5, 2, 4, 2, 0] * ] * }; * * // In addition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries. * var responsiveOptions = [ * ['screen and (min-width: 641px) and (max-width: 1024px)', { * showPoint: false, * axisX: { * labelInterpolationFnc: function(value) { * // Will return Mon, Tue, Wed etc. on medium screens * return value.slice(0, 3); * } * } * }], * ['screen and (max-width: 640px)', { * showLine: false, * axisX: { * labelInterpolationFnc: function(value) { * // Will return M, T, W etc. on small screens * return value[0]; * } * } * }] * ]; * * new Chartist.Line('.ct-chart', data, null, responsiveOptions); * */ function Line(query, data, options, responsiveOptions) { Chartist.Line.super.constructor.call(this, query, data, defaultOptions, Chartist.extend({}, defaultOptions, options), responsiveOptions); } // Creating line chart type in Chartist namespace Chartist.Line = Chartist.Base.extend({ constructor: Line, createChart: createChart }); }(window, document, Chartist)); ;/** * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts. * * @module Chartist.Bar */ /* global Chartist */ (function(window, document, Chartist){ 'use strict'; /** * Default options in bar charts. Expand the code view to see a detailed list of options with comments. * * @memberof Chartist.Bar */ var defaultOptions = { // Options for X-Axis axisX: { // The offset of the chart drawing area to the border of the container offset: 30, // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis. position: 'end', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, // If labels should be shown or not showLabel: true, // If the axis grid should be drawn or not showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // This value specifies the minimum width in pixel of the scale steps scaleMinSpace: 30, // Use only integer values (whole numbers) for the scale steps onlyInteger: false }, // Options for Y-Axis axisY: { // The offset of the chart drawing area to the border of the container offset: 40, // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis. position: 'start', // Allows you to correct label positioning on this axis by positive or negative x and y offset. labelOffset: { x: 0, y: 0 }, // If labels should be shown or not showLabel: true, // If the axis grid should be drawn or not showGrid: true, // Interpolation function that allows you to intercept the value from the axis label labelInterpolationFnc: Chartist.noop, // This value specifies the minimum height in pixel of the scale steps scaleMinSpace: 20, // Use only integer values (whole numbers) for the scale steps onlyInteger: false }, // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') height: undefined, // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value high: undefined, // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value low: undefined, // Unless low/high are explicitly set, bar chart will be centered at zero by default. Set referenceValue to null to auto scale. referenceValue: 0, // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5} chartPadding: { top: 15, right: 15, bottom: 5, left: 10 }, // Specify the distance in pixel of bars in a group seriesBarDistance: 15, // If set to true this property will cause the series bars to be stacked. Check the `stackMode` option for further stacking options. stackBars: false, // If set to 'overlap' this property will force the stacked bars to draw from the zero line. // If set to 'accumulate' this property will form a total for each series point. This will also influence the y-axis and the overall bounds of the chart. In stacked mode the seriesBarDistance property will have no effect. stackMode: 'accumulate', // Inverts the axes of the bar chart in order to draw a horizontal bar chart. Be aware that you also need to invert your axis settings as the Y Axis will now display the labels and the X Axis the values. horizontalBars: false, // If set to true then each bar will represent a series and the data array is expected to be a one dimensional array of data values rather than a series array of series. This is useful if the bar chart should represent a profile rather than some data over time. distributeSeries: false, // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. reverseData: false, // If the bar chart should add a background fill to the .ct-grids group. showGridBackground: false, // Override the class names that get used to generate the SVG structure of the chart classNames: { chart: 'ct-chart-bar', horizontalBars: 'ct-horizontal-bars', label: 'ct-label', labelGroup: 'ct-labels', series: 'ct-series', bar: 'ct-bar', grid: 'ct-grid', gridGroup: 'ct-grids', gridBackground: 'ct-grid-background', vertical: 'ct-vertical', horizontal: 'ct-horizontal', start: 'ct-start', end: 'ct-end' } }; /** * Creates a new chart * */ function createChart(options) { var data; var highLow; if(options.distributeSeries) { data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); data.normalized.series = data.normalized.series.map(function(value) { return [value]; }); } else { data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y'); } // Create new svg element this.svg = Chartist.createSvg( this.container, options.width, options.height, options.classNames.chart + (options.horizontalBars ? ' ' + options.classNames.horizontalBars : '') ); // Drawing groups in correct order var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup); var seriesGroup = this.svg.elem('g'); var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup); if(options.stackBars && data.normalized.series.length !== 0) { // If stacked bars we need to calculate the high low from stacked values from each series var serialSums = Chartist.serialMap(data.normalized.series, function serialSums() { return Array.prototype.slice.call(arguments).map(function(value) { return value; }).reduce(function(prev, curr) { return { x: prev.x + (curr && curr.x) || 0, y: prev.y + (curr && curr.y) || 0 }; }, {x: 0, y: 0}); }); highLow = Chartist.getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y'); } else { highLow = Chartist.getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y'); } // Overrides of high / low from settings highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high); highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low); var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); var valueAxis, labelAxisTicks, labelAxis, axisX, axisY; // We need to set step count based on some options combinations if(options.distributeSeries && options.stackBars) { // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should // use only the first label for the step axis labelAxisTicks = data.normalized.labels.slice(0, 1); } else { // If distributed series are enabled but stacked bars aren't, we should use the series labels // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array // as the bars are normalized labelAxisTicks = data.normalized.labels; } // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary. if(options.horizontalBars) { if(options.axisX.type === undefined) { valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, { highLow: highLow, referenceValue: 0 })); } else { valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, { highLow: highLow, referenceValue: 0 })); } if(options.axisY.type === undefined) { labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, { ticks: labelAxisTicks }); } else { labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY); } } else { if(options.axisX.type === undefined) { labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, { ticks: labelAxisTicks }); } else { labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX); } if(options.axisY.type === undefined) { valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, { highLow: highLow, referenceValue: 0 })); } else { valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, { highLow: highLow, referenceValue: 0 })); } } // Projected 0 point var zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0)) : (chartRect.y1 - valueAxis.projectValue(0)); // Used to track the screen coordinates of stacked bars var stackedBarValues = []; labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter); if (options.showGridBackground) { Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter); } // Draw the series data.raw.series.forEach(function(series, seriesIndex) { // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc. var biPol = seriesIndex - (data.raw.series.length - 1) / 2; // Half of the period width between vertical grid lines used to position bars var periodHalfLength; // Current series SVG element var seriesElement; // We need to set periodHalfLength based on some options combinations if(options.distributeSeries && !options.stackBars) { // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array // which is the series count and divide by 2 periodHalfLength = labelAxis.axisLength / data.normalized.series.length / 2; } else if(options.distributeSeries && options.stackBars) { // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis // length by 2 periodHalfLength = labelAxis.axisLength / 2; } else { // On regular bar charts we should just use the series length periodHalfLength = labelAxis.axisLength / data.normalized.series[seriesIndex].length / 2; } // Adding the series group to the series element seriesElement = seriesGroup.elem('g'); // Write attributes to series group element. If series name or meta is undefined the attributes will not be written seriesElement.attr({ 'ct:series-name': series.name, 'ct:meta': Chartist.serialize(series.meta) }); // Use series class from series data or if not set generate one seriesElement.addClass([ options.classNames.series, (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex)) ].join(' ')); data.normalized.series[seriesIndex].forEach(function(value, valueIndex) { var projected, bar, previousStack, labelAxisValueIndex; // We need to set labelAxisValueIndex based on some options combinations if(options.distributeSeries && !options.stackBars) { // If distributed series are enabled but stacked bars aren't, we can use the seriesIndex for later projection // on the step axis for label positioning labelAxisValueIndex = seriesIndex; } else if(options.distributeSeries && options.stackBars) { // If distributed series and stacked bars are enabled, we will only get one bar and therefore always use // 0 for projection on the label step axis labelAxisValueIndex = 0; } else { // On regular bar charts we just use the value index to project on the label step axis labelAxisValueIndex = valueIndex; } // We need to transform coordinates differently based on the chart layout if(options.horizontalBars) { projected = { x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized.series[seriesIndex]), y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]) }; } else { projected = { x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]), y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized.series[seriesIndex]) } } // If the label axis is a step based axis we will offset the bar into the middle of between two steps using // the periodHalfLength value. Also we do arrange the different series so that they align up to each other using // the seriesBarDistance. If we don't have a step axis, the bar positions can be chosen freely so we should not // add any automated positioning. if(labelAxis instanceof Chartist.StepAxis) { // Offset to center bar between grid lines, but only if the step axis is not stretched if(!labelAxis.options.stretch) { projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1); } // Using bi-polar offset for multiple series if no stacked bars or series distribution is used projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1); } // Enter value in stacked bar values used to remember previous screen value for stacking up bars previousStack = stackedBarValues[valueIndex] || zeroPoint; stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]); // Skip if value is undefined if(value === undefined) { return; } var positions = {}; positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos]; positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos]; if(options.stackBars && (options.stackMode === 'accumulate' || !options.stackMode)) { // Stack mode: accumulate (default) // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line // We want backwards compatibility, so the expected fallback without the 'stackMode' option // to be the original behaviour (accumulate) positions[labelAxis.counterUnits.pos + '1'] = previousStack; positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex]; } else { // Draw from the zero line normally // This is also the same code for Stack mode: overlap positions[labelAxis.counterUnits.pos + '1'] = zeroPoint; positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos]; } // Limit x and y so that they are within the chart rect positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2); positions.x2 = Math.min(Math.max(positions.x2, chartRect.x1), chartRect.x2); positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1); positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1); var metaData = Chartist.getMetaData(series, valueIndex); // Create bar element bar = seriesElement.elem('line', positions, options.classNames.bar).attr({ 'ct:value': [value.x, value.y].filter(Chartist.isNumeric).join(','), 'ct:meta': Chartist.serialize(metaData) }); this.eventEmitter.emit('draw', Chartist.extend({ type: 'bar', value: value, index: valueIndex, meta: metaData, series: series, seriesIndex: seriesIndex, axisX: axisX, axisY: axisY, chartRect: chartRect, group: seriesElement, element: bar }, positions)); }.bind(this)); }.bind(this)); this.eventEmitter.emit('created', { bounds: valueAxis.bounds, chartRect: chartRect, axisX: axisX, axisY: axisY, svg: this.svg, options: options }); } /** * This method creates a new bar chart and returns API object that you can use for later changes. * * @memberof Chartist.Bar * @param {String|Node} query A selector query string or directly a DOM element * @param {Object} data The data object that needs to consist of a labels and a series array * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] * @return {Object} An object which exposes the API for the created chart * * @example * // Create a simple bar chart * var data = { * labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], * series: [ * [5, 2, 4, 2, 0] * ] * }; * * // In the global name space Chartist we call the Bar function to initialize a bar chart. As a first parameter we pass in a selector where we would like to get our chart created and as a second parameter we pass our data object. * new Chartist.Bar('.ct-chart', data); * * @example * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10 * new Chartist.Bar('.ct-chart', { * labels: [1, 2, 3, 4, 5, 6, 7], * series: [ * [1, 3, 2, -5, -3, 1, -6], * [-5, -2, -4, -1, 2, -3, 1] * ] * }, { * seriesBarDistance: 12, * low: -10, * high: 10 * }); * */ function Bar(query, data, options, responsiveOptions) { Chartist.Bar.super.constructor.call(this, query, data, defaultOptions, Chartist.extend({}, defaultOptions, options), responsiveOptions); } // Creating bar chart type in Chartist namespace Chartist.Bar = Chartist.Base.extend({ constructor: Bar, createChart: createChart }); }(window, document, Chartist)); ;/** * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts * * @module Chartist.Pie */ /* global Chartist */ (function(window, document, Chartist) { 'use strict'; /** * Default options in line charts. Expand the code view to see a detailed list of options with comments. * * @memberof Chartist.Pie */ var defaultOptions = { // Specify a fixed width for the chart as a string (i.e. '100px' or '50%') width: undefined, // Specify a fixed height for the chart as a string (i.e. '100px' or '50%') height: undefined, // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5} chartPadding: 5, // Override the class names that are used to generate the SVG structure of the chart classNames: { chartPie: 'ct-chart-pie', chartDonut: 'ct-chart-donut', series: 'ct-series', slicePie: 'ct-slice-pie', sliceDonut: 'ct-slice-donut', sliceDonutSolid: 'ct-slice-donut-solid', label: 'ct-label' }, // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise. startAngle: 0, // An optional total you can specify. By specifying a total value, the sum of the values in the series must be this total in order to draw a full pie. You can use this parameter to draw only parts of a pie or gauge charts. total: undefined, // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices. donut: false, // If specified the donut segments will be drawn as shapes instead of strokes. donutSolid: false, // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future. // This option can be set as number or string to specify a relative width (i.e. 100 or '30%'). donutWidth: 60, // If a label should be shown or not showLabel: true, // Label position offset from the standard position which is half distance of the radius. This value can be either positive or negative. Positive values will position the label away from the center. labelOffset: 0, // This option can be set to 'inside', 'outside' or 'center'. Positioned with 'inside' the labels will be placed on half the distance of the radius to the border of the Pie by respecting the 'labelOffset'. The 'outside' option will place the labels at the border of the pie and 'center' will place the labels in the absolute center point of the chart. The 'center' option only makes sense in conjunction with the 'labelOffset' option. labelPosition: 'inside', // An interpolation function for the label value labelInterpolationFnc: Chartist.noop, // Label direction can be 'neutral', 'explode' or 'implode'. The labels anchor will be positioned based on those settings as well as the fact if the labels are on the right or left side of the center of the chart. Usually explode is useful when labels are positioned far away from the center. labelDirection: 'neutral', // If true the whole data is reversed including labels, the series order as well as the whole series data arrays. reverseData: false, // If true empty values will be ignored to avoid drawing unncessary slices and labels ignoreEmptyValues: false }; /** * Determines SVG anchor position based on direction and center parameter * * @param center * @param label * @param direction * @return {string} */ function determineAnchorPosition(center, label, direction) { var toTheRight = label.x > center.x; if(toTheRight && direction === 'explode' || !toTheRight && direction === 'implode') { return 'start'; } else if(toTheRight && direction === 'implode' || !toTheRight && direction === 'explode') { return 'end'; } else { return 'middle'; } } /** * Creates the pie chart * * @param options */ function createChart(options) { var data = Chartist.normalizeData(this.data); var seriesGroups = [], labelsGroup, chartRect, radius, labelRadius, totalDataSum, startAngle = options.startAngle; // Create SVG.js draw this.svg = Chartist.createSvg(this.container, options.width, options.height,options.donut ? options.classNames.chartDonut : options.classNames.chartPie); // Calculate charting rect chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding); // Get biggest circle radius possible within chartRect radius = Math.min(chartRect.width() / 2, chartRect.height() / 2); // Calculate total of all series to get reference value or use total reference from optional options totalDataSum = options.total || data.normalized.series.reduce(function(previousValue, currentValue) { return previousValue + currentValue; }, 0); var donutWidth = Chartist.quantity(options.donutWidth); if (donutWidth.unit === '%') { donutWidth.value *= radius / 100; } // If this is a donut chart we need to adjust our radius to enable strokes to be drawn inside // Unfortunately this is not possible with the current SVG Spec // See this proposal for more details: http://lists.w3.org/Archives/Public/www-svg/2003Oct/0000.html radius -= options.donut && !options.donutSolid ? donutWidth.value / 2 : 0; // If labelPosition is set to `outside` or a donut chart is drawn then the label position is at the radius, // if regular pie chart it's half of the radius if(options.labelPosition === 'outside' || options.donut && !options.donutSolid) { labelRadius = radius; } else if(options.labelPosition === 'center') { // If labelPosition is center we start with 0 and will later wait for the labelOffset labelRadius = 0; } else if(options.donutSolid) { labelRadius = radius - donutWidth.value / 2; } else { // Default option is 'inside' where we use half the radius so the label will be placed in the center of the pie // slice labelRadius = radius / 2; } // Add the offset to the labelRadius where a negative offset means closed to the center of the chart labelRadius += options.labelOffset; // Calculate end angle based on total sum and current data value and offset with padding var center = { x: chartRect.x1 + chartRect.width() / 2, y: chartRect.y2 + chartRect.height() / 2 }; // Check if there is only one non-zero value in the series array. var hasSingleValInSeries = data.raw.series.filter(function(val) { return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0; }).length === 1; // Creating the series groups data.raw.series.forEach(function(series, index) { seriesGroups[index] = this.svg.elem('g', null, null); }.bind(this)); //if we need to show labels we create the label group now if(options.showLabel) { labelsGroup = this.svg.elem('g', null, null); } // Draw the series // initialize series groups data.raw.series.forEach(function(series, index) { // If current value is zero and we are ignoring empty values then skip to next value if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return; // If the series is an object and contains a name or meta data we add a custom attribute seriesGroups[index].attr({ 'ct:series-name': series.name }); // Use series class from series data or if not set generate one seriesGroups[index].addClass([ options.classNames.series, (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(index)) ].join(' ')); // If the whole dataset is 0 endAngle should be zero. Can't divide by 0. var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0); // Use slight offset so there are no transparent hairline issues var overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2)); // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle // with Z and use 359.99 degrees if(endAngle - overlappigStartAngle >= 359.99) { endAngle = overlappigStartAngle + 359.99; } var start = Chartist.polarToCartesian(center.x, center.y, radius, overlappigStartAngle), end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle); var innerStart, innerEnd, donutSolidRadius; // Create a new path element for the pie chart. If this isn't a donut chart we should close the path for a correct stroke var path = new Chartist.Svg.Path(!options.donut || options.donutSolid) .move(end.x, end.y) .arc(radius, radius, 0, endAngle - startAngle > 180, 0, start.x, start.y); // If regular pie chart (no donut) we add a line to the center of the circle for completing the pie if(!options.donut) { path.line(center.x, center.y); } else if (options.donutSolid) { donutSolidRadius = radius - donutWidth.value; innerStart = Chartist.polarToCartesian(center.x, center.y, donutSolidRadius, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2)); innerEnd = Chartist.polarToCartesian(center.x, center.y, donutSolidRadius, endAngle); path.line(innerStart.x, innerStart.y); path.arc(donutSolidRadius, donutSolidRadius, 0, endAngle - startAngle > 180, 1, innerEnd.x, innerEnd.y); } // Create the SVG path // If this is a donut chart we add the donut class, otherwise just a regular slice var pathClassName = options.classNames.slicePie; if (options.donut) { pathClassName = options.classNames.sliceDonut; if (options.donutSolid) { pathClassName = options.classNames.sliceDonutSolid; } } var pathElement = seriesGroups[index].elem('path', { d: path.stringify() }, pathClassName); // Adding the pie series value to the path pathElement.attr({ 'ct:value': data.normalized.series[index], 'ct:meta': Chartist.serialize(series.meta) }); // If this is a donut, we add the stroke-width as style attribute if(options.donut && !options.donutSolid) { pathElement._node.style.strokeWidth = donutWidth.value + 'px'; } // Fire off draw event this.eventEmitter.emit('draw', { type: 'slice', value: data.normalized.series[index], totalDataSum: totalDataSum, index: index, meta: series.meta, series: series, group: seriesGroups[index], element: pathElement, path: path.clone(), center: center, radius: radius, startAngle: startAngle, endAngle: endAngle }); // If we need to show labels we need to add the label for this slice now if(options.showLabel) { var labelPosition; if(data.raw.series.length === 1) { // If we have only 1 series, we can position the label in the center of the pie labelPosition = { x: center.x, y: center.y }; } else { // Position at the labelRadius distance from center and between start and end angle labelPosition = Chartist.polarToCartesian( center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2 ); } var rawValue; if(data.normalized.labels && !Chartist.isFalseyButZero(data.normalized.labels[index])) { rawValue = data.normalized.labels[index]; } else { rawValue = data.normalized.series[index]; } var interpolatedValue = options.labelInterpolationFnc(rawValue, index); if(interpolatedValue || interpolatedValue === 0) { var labelElement = labelsGroup.elem('text', { dx: labelPosition.x, dy: labelPosition.y, 'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection) }, options.classNames.label).text('' + interpolatedValue); // Fire off draw event this.eventEmitter.emit('draw', { type: 'label', index: index, group: labelsGroup, element: labelElement, text: '' + interpolatedValue, x: labelPosition.x, y: labelPosition.y }); } } // Set next startAngle to current endAngle. // (except for last slice) startAngle = endAngle; }.bind(this)); this.eventEmitter.emit('created', { chartRect: chartRect, svg: this.svg, options: options }); } /** * This method creates a new pie chart and returns an object that can be used to redraw the chart. * * @memberof Chartist.Pie * @param {String|Node} query A selector query string or directly a DOM element * @param {Object} data The data object in the pie chart needs to have a series property with a one dimensional data array. The values will be normalized against each other and don't necessarily need to be in percentage. The series property can also be an array of value objects that contain a value property and a className property to override the CSS class name for the series group. * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list. * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]] * @return {Object} An object with a version and an update method to manually redraw the chart * * @example * // Simple pie chart example with four series * new Chartist.Pie('.ct-chart', { * series: [10, 2, 4, 3] * }); * * @example * // Drawing a donut chart * new Chartist.Pie('.ct-chart', { * series: [10, 2, 4, 3] * }, { * donut: true * }); * * @example * // Using donut, startAngle and total to draw a gauge chart * new Chartist.Pie('.ct-chart', { * series: [20, 10, 30, 40] * }, { * donut: true, * donutWidth: 20, * startAngle: 270, * total: 200 * }); * * @example * // Drawing a pie chart with padding and labels that are outside the pie * new Chartist.Pie('.ct-chart', { * series: [20, 10, 30, 40] * }, { * chartPadding: 30, * labelOffset: 50, * labelDirection: 'explode' * }); * * @example * // Overriding the class names for individual series as well as a name and meta data. * // The name will be written as ct:series-name attribute and the meta data will be serialized and written * // to a ct:meta attribute. * new Chartist.Pie('.ct-chart', { * series: [{ * value: 20, * name: 'Series 1', * className: 'my-custom-class-one', * meta: 'Meta One' * }, { * value: 10, * name: 'Series 2', * className: 'my-custom-class-two', * meta: 'Meta Two' * }, { * value: 70, * name: 'Series 3', * className: 'my-custom-class-three', * meta: 'Meta Three' * }] * }); */ function Pie(query, data, options, responsiveOptions) { Chartist.Pie.super.constructor.call(this, query, data, defaultOptions, Chartist.extend({}, defaultOptions, options), responsiveOptions); } // Creating pie chart type in Chartist namespace Chartist.Pie = Chartist.Base.extend({ constructor: Pie, createChart: createChart, determineAnchorPosition: determineAnchorPosition }); }(window, document, Chartist)); return Chartist; })); SABnzbd-2.3.2/interfaces/Config/templates/staticcfg/js/src/jquery-3.2.1.js0000644000000000000000000101340713167643637024541 0ustar rootroot/*! * jQuery JavaScript Library v3.2.1 * https://jquery.com/ * * Includes Sizzle.js * https://sizzlejs.com/ * * Copyright JS Foundation and other contributors * Released under the MIT license * https://jquery.org/license * * Date: 2017-03-20T18:59Z */ ( function( global, factory ) { "use strict"; if ( typeof module === "object" && typeof module.exports === "object" ) { // For CommonJS and CommonJS-like environments where a proper `window` // is present, execute the factory and get jQuery. // For environments that do not have a `window` with a `document` // (such as Node.js), expose a factory as module.exports. // This accentuates the need for the creation of a real `window`. // e.g. var jQuery = require("jquery")(window); // See ticket #14549 for more info. module.exports = global.document ? factory( global, true ) : function( w ) { if ( !w.document ) { throw new Error( "jQuery requires a window with a document" ); } return factory( w ); }; } else { factory( global ); } // Pass this if window is not defined yet } )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { // Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 // throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode // arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common // enough that all such attempts are guarded in a try block. "use strict"; var arr = []; var document = window.document; var getProto = Object.getPrototypeOf; var slice = arr.slice; var concat = arr.concat; var push = arr.push; var indexOf = arr.indexOf; var class2type = {}; var toString = class2type.toString; var hasOwn = class2type.hasOwnProperty; var fnToString = hasOwn.toString; var ObjectFunctionString = fnToString.call( Object ); var support = {}; function DOMEval( code, doc ) { doc = doc || document; var script = doc.createElement( "script" ); script.text = code; doc.head.appendChild( script ).parentNode.removeChild( script ); } /* global Symbol */ // Defining this global in .eslintrc.json would create a danger of using the global // unguarded in another place, it seems safer to define global only for this module var version = "3.2.1", // Define a local copy of jQuery jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' // Need init if jQuery is called (just allow error to be thrown if not included) return new jQuery.fn.init( selector, context ); }, // Support: Android <=4.0 only // Make sure we trim BOM and NBSP rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, // Matches dashed string for camelizing rmsPrefix = /^-ms-/, rdashAlpha = /-([a-z])/g, // Used by jQuery.camelCase as callback to replace() fcamelCase = function( all, letter ) { return letter.toUpperCase(); }; jQuery.fn = jQuery.prototype = { // The current version of jQuery being used jquery: version, constructor: jQuery, // The default length of a jQuery object is 0 length: 0, toArray: function() { return slice.call( this ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { // Return all the elements in a clean array if ( num == null ) { return slice.call( this ); } // Return just the one element from the set return num < 0 ? this[ num + this.length ] : this[ num ]; }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems ) { // Build a new jQuery matched element set var ret = jQuery.merge( this.constructor(), elems ); // Add the old object onto the stack (as a reference) ret.prevObject = this; // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. each: function( callback ) { return jQuery.each( this, callback ); }, map: function( callback ) { return this.pushStack( jQuery.map( this, function( elem, i ) { return callback.call( elem, i, elem ); } ) ); }, slice: function() { return this.pushStack( slice.apply( this, arguments ) ); }, first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, eq: function( i ) { var len = this.length, j = +i + ( i < 0 ? len : 0 ); return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); }, end: function() { return this.prevObject || this.constructor(); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: push, sort: arr.sort, splice: arr.splice }; jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[ 0 ] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; // Skip the boolean and the target target = arguments[ i ] || {}; i++; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { target = {}; } // Extend jQuery itself if only one argument is passed if ( i === length ) { target = this; i--; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( ( options = arguments[ i ] ) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject( copy ) || ( copyIsArray = Array.isArray( copy ) ) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && Array.isArray( src ) ? src : []; } else { clone = src && jQuery.isPlainObject( src ) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend( { // Unique for each copy of jQuery on the page expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), // Assume jQuery is ready without the ready module isReady: true, error: function( msg ) { throw new Error( msg ); }, noop: function() {}, isFunction: function( obj ) { return jQuery.type( obj ) === "function"; }, isWindow: function( obj ) { return obj != null && obj === obj.window; }, isNumeric: function( obj ) { // As of jQuery 3.0, isNumeric is limited to // strings and numbers (primitives or objects) // that can be coerced to finite numbers (gh-2662) var type = jQuery.type( obj ); return ( type === "number" || type === "string" ) && // parseFloat NaNs numeric-cast false positives ("") // ...but misinterprets leading-number strings, particularly hex literals ("0x...") // subtraction forces infinities to NaN !isNaN( obj - parseFloat( obj ) ); }, isPlainObject: function( obj ) { var proto, Ctor; // Detect obvious negatives // Use toString instead of jQuery.type to catch host objects if ( !obj || toString.call( obj ) !== "[object Object]" ) { return false; } proto = getProto( obj ); // Objects with no prototype (e.g., `Object.create( null )`) are plain if ( !proto ) { return true; } // Objects with prototype are plain iff they were constructed by a global Object function Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; }, isEmptyObject: function( obj ) { /* eslint-disable no-unused-vars */ // See https://github.com/eslint/eslint/issues/6125 var name; for ( name in obj ) { return false; } return true; }, type: function( obj ) { if ( obj == null ) { return obj + ""; } // Support: Android <=2.3 only (functionish RegExp) return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call( obj ) ] || "object" : typeof obj; }, // Evaluates a script in a global context globalEval: function( code ) { DOMEval( code ); }, // Convert dashed to camelCase; used by the css and data modules // Support: IE <=9 - 11, Edge 12 - 13 // Microsoft forgot to hump their vendor prefix (#9572) camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, each: function( obj, callback ) { var length, i = 0; if ( isArrayLike( obj ) ) { length = obj.length; for ( ; i < length; i++ ) { if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { break; } } } else { for ( i in obj ) { if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { break; } } } return obj; }, // Support: Android <=4.0 only trim: function( text ) { return text == null ? "" : ( text + "" ).replace( rtrim, "" ); }, // results is for internal usage only makeArray: function( arr, results ) { var ret = results || []; if ( arr != null ) { if ( isArrayLike( Object( arr ) ) ) { jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr ); } else { push.call( ret, arr ); } } return ret; }, inArray: function( elem, arr, i ) { return arr == null ? -1 : indexOf.call( arr, elem, i ); }, // Support: Android <=4.0 only, PhantomJS 1 only // push.apply(_, arraylike) throws on ancient WebKit merge: function( first, second ) { var len = +second.length, j = 0, i = first.length; for ( ; j < len; j++ ) { first[ i++ ] = second[ j ]; } first.length = i; return first; }, grep: function( elems, callback, invert ) { var callbackInverse, matches = [], i = 0, length = elems.length, callbackExpect = !invert; // Go through the array, only saving the items // that pass the validator function for ( ; i < length; i++ ) { callbackInverse = !callback( elems[ i ], i ); if ( callbackInverse !== callbackExpect ) { matches.push( elems[ i ] ); } } return matches; }, // arg is for internal usage only map: function( elems, callback, arg ) { var length, value, i = 0, ret = []; // Go through the array, translating each of the items to their new values if ( isArrayLike( elems ) ) { length = elems.length; for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } // Go through every key on the object, } else { for ( i in elems ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } } // Flatten any nested arrays return concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { var tmp, args, proxy; if ( typeof context === "string" ) { tmp = fn[ context ]; context = fn; fn = tmp; } // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. if ( !jQuery.isFunction( fn ) ) { return undefined; } // Simulated bind args = slice.call( arguments, 2 ); proxy = function() { return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); }; // Set the guid of unique handler to the same of original handler, so it can be removed proxy.guid = fn.guid = fn.guid || jQuery.guid++; return proxy; }, now: Date.now, // jQuery.support is not used in Core but other projects attach their // properties to it so it needs to exist. support: support } ); if ( typeof Symbol === "function" ) { jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; } // Populate the class2type map jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), function( i, name ) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); } ); function isArrayLike( obj ) { // Support: real iOS 8.2 only (not reproducible in simulator) // `in` check used to prevent JIT error (gh-2145) // hasOwn isn't used here due to false negatives // regarding Nodelist length in IE var length = !!obj && "length" in obj && obj.length, type = jQuery.type( obj ); if ( type === "function" || jQuery.isWindow( obj ) ) { return false; } return type === "array" || length === 0 || typeof length === "number" && length > 0 && ( length - 1 ) in obj; } var Sizzle = /*! * Sizzle CSS Selector Engine v2.3.3 * https://sizzlejs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2016-08-08 */ (function( window ) { var i, support, Expr, getText, isXML, tokenize, compile, select, outermostContext, sortInput, hasDuplicate, // Local document vars setDocument, document, docElem, documentIsHTML, rbuggyQSA, rbuggyMatches, matches, contains, // Instance-specific data expando = "sizzle" + 1 * new Date(), preferredDoc = window.document, dirruns = 0, done = 0, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; } return 0; }, // Instance methods hasOwn = ({}).hasOwnProperty, arr = [], pop = arr.pop, push_native = arr.push, push = arr.push, slice = arr.slice, // Use a stripped-down indexOf as it's faster than native // https://jsperf.com/thor-indexof-vs-for/5 indexOf = function( list, elem ) { var i = 0, len = list.length; for ( ; i < len; i++ ) { if ( list[i] === elem ) { return i; } } return -1; }, booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", // Regular expressions // http://www.w3.org/TR/css3-selectors/#whitespace whitespace = "[\\x20\\t\\r\\n\\f]", // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + // Operator (capture 2) "*([*^$|!~]?=)" + whitespace + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]", pseudos = ":(" + identifier + ")(?:\\((" + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: // 1. quoted (capture 3; capture 4 or capture 5) "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + // 2. simple (capture 6) "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + // 3. anything else (capture 2) ".*" + ")\\)|)", // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter rwhitespace = new RegExp( whitespace + "+", "g" ), rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), rpseudo = new RegExp( pseudos ), ridentifier = new RegExp( "^" + identifier + "$" ), matchExpr = { "ID": new RegExp( "^#(" + identifier + ")" ), "CLASS": new RegExp( "^\\.(" + identifier + ")" ), "TAG": new RegExp( "^(" + identifier + "|[*])" ), "ATTR": new RegExp( "^" + attributes ), "PSEUDO": new RegExp( "^" + pseudos ), "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), // For use in libraries implementing .is() // We use this for POS matching in `select` "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rnative = /^[^{]+\{\s*\[native \w/, // Easily-parseable/retrievable ID or TAG or CLASS selectors rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rsibling = /[+~]/, // CSS escapes // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), funescape = function( _, escaped, escapedWhitespace ) { var high = "0x" + escaped - 0x10000; // NaN means non-codepoint // Support: Firefox<24 // Workaround erroneous numeric interpretation of +"0x" return high !== high || escapedWhitespace ? escaped : high < 0 ? // BMP codepoint String.fromCharCode( high + 0x10000 ) : // Supplemental Plane codepoint (surrogate pair) String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); }, // CSS string/identifier serialization // https://drafts.csswg.org/cssom/#common-serializing-idioms rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, fcssescape = function( ch, asCodePoint ) { if ( asCodePoint ) { // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER if ( ch === "\0" ) { return "\uFFFD"; } // Control characters and (dependent upon position) numbers get escaped as code points return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; } // Other potentially-special ASCII characters get backslash-escaped return "\\" + ch; }, // Used for iframes // See setDocument() // Removing the function wrapper causes a "Permission Denied" // error in IE unloadHandler = function() { setDocument(); }, disabledAncestor = addCombinator( function( elem ) { return elem.disabled === true && ("form" in elem || "label" in elem); }, { dir: "parentNode", next: "legend" } ); // Optimize for push.apply( _, NodeList ) try { push.apply( (arr = slice.call( preferredDoc.childNodes )), preferredDoc.childNodes ); // Support: Android<4.0 // Detect silently failing push.apply arr[ preferredDoc.childNodes.length ].nodeType; } catch ( e ) { push = { apply: arr.length ? // Leverage slice if possible function( target, els ) { push_native.apply( target, slice.call(els) ); } : // Support: IE<9 // Otherwise append directly function( target, els ) { var j = target.length, i = 0; // Can't trust NodeList.length while ( (target[j++] = els[i++]) ) {} target.length = j - 1; } }; } function Sizzle( selector, context, results, seed ) { var m, i, elem, nid, match, groups, newSelector, newContext = context && context.ownerDocument, // nodeType defaults to 9, since context defaults to document nodeType = context ? context.nodeType : 9; results = results || []; // Return early from calls with invalid selector or context if ( typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { return results; } // Try to shortcut find operations (as opposed to filters) in HTML documents if ( !seed ) { if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { setDocument( context ); } context = context || document; if ( documentIsHTML ) { // If the selector is sufficiently simple, try using a "get*By*" DOM method // (excepting DocumentFragment context, where the methods don't exist) if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { // ID selector if ( (m = match[1]) ) { // Document context if ( nodeType === 9 ) { if ( (elem = context.getElementById( m )) ) { // Support: IE, Opera, Webkit // TODO: identify versions // getElementById can match elements by name instead of ID if ( elem.id === m ) { results.push( elem ); return results; } } else { return results; } // Element context } else { // Support: IE, Opera, Webkit // TODO: identify versions // getElementById can match elements by name instead of ID if ( newContext && (elem = newContext.getElementById( m )) && contains( context, elem ) && elem.id === m ) { results.push( elem ); return results; } } // Type selector } else if ( match[2] ) { push.apply( results, context.getElementsByTagName( selector ) ); return results; // Class selector } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { push.apply( results, context.getElementsByClassName( m ) ); return results; } } // Take advantage of querySelectorAll if ( support.qsa && !compilerCache[ selector + " " ] && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { if ( nodeType !== 1 ) { newContext = context; newSelector = selector; // qSA looks outside Element context, which is not what we want // Thanks to Andrew Dupont for this workaround technique // Support: IE <=8 // Exclude object elements } else if ( context.nodeName.toLowerCase() !== "object" ) { // Capture the context ID, setting it first if necessary if ( (nid = context.getAttribute( "id" )) ) { nid = nid.replace( rcssescape, fcssescape ); } else { context.setAttribute( "id", (nid = expando) ); } // Prefix every selector in the list groups = tokenize( selector ); i = groups.length; while ( i-- ) { groups[i] = "#" + nid + " " + toSelector( groups[i] ); } newSelector = groups.join( "," ); // Expand context for sibling selectors newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; } if ( newSelector ) { try { push.apply( results, newContext.querySelectorAll( newSelector ) ); return results; } catch ( qsaError ) { } finally { if ( nid === expando ) { context.removeAttribute( "id" ); } } } } } } // All others return select( selector.replace( rtrim, "$1" ), context, results, seed ); } /** * Create key-value caches of limited size * @returns {function(string, object)} Returns the Object data after storing it on itself with * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) * deleting the oldest entry */ function createCache() { var keys = []; function cache( key, value ) { // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) if ( keys.push( key + " " ) > Expr.cacheLength ) { // Only keep the most recent entries delete cache[ keys.shift() ]; } return (cache[ key + " " ] = value); } return cache; } /** * Mark a function for special use by Sizzle * @param {Function} fn The function to mark */ function markFunction( fn ) { fn[ expando ] = true; return fn; } /** * Support testing using an element * @param {Function} fn Passed the created element and returns a boolean result */ function assert( fn ) { var el = document.createElement("fieldset"); try { return !!fn( el ); } catch (e) { return false; } finally { // Remove from its parent by default if ( el.parentNode ) { el.parentNode.removeChild( el ); } // release memory in IE el = null; } } /** * Adds the same handler for all of the specified attrs * @param {String} attrs Pipe-separated list of attributes * @param {Function} handler The method that will be applied */ function addHandle( attrs, handler ) { var arr = attrs.split("|"), i = arr.length; while ( i-- ) { Expr.attrHandle[ arr[i] ] = handler; } } /** * Checks document order of two siblings * @param {Element} a * @param {Element} b * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b */ function siblingCheck( a, b ) { var cur = b && a, diff = cur && a.nodeType === 1 && b.nodeType === 1 && a.sourceIndex - b.sourceIndex; // Use IE sourceIndex if available on both nodes if ( diff ) { return diff; } // Check if b follows a if ( cur ) { while ( (cur = cur.nextSibling) ) { if ( cur === b ) { return -1; } } } return a ? 1 : -1; } /** * Returns a function to use in pseudos for input types * @param {String} type */ function createInputPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === type; }; } /** * Returns a function to use in pseudos for buttons * @param {String} type */ function createButtonPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && elem.type === type; }; } /** * Returns a function to use in pseudos for :enabled/:disabled * @param {Boolean} disabled true for :disabled; false for :enabled */ function createDisabledPseudo( disabled ) { // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable return function( elem ) { // Only certain elements can match :enabled or :disabled // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled if ( "form" in elem ) { // Check for inherited disabledness on relevant non-disabled elements: // * listed form-associated elements in a disabled fieldset // https://html.spec.whatwg.org/multipage/forms.html#category-listed // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled // * option elements in a disabled optgroup // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled // All such elements have a "form" property. if ( elem.parentNode && elem.disabled === false ) { // Option elements defer to a parent optgroup if present if ( "label" in elem ) { if ( "label" in elem.parentNode ) { return elem.parentNode.disabled === disabled; } else { return elem.disabled === disabled; } } // Support: IE 6 - 11 // Use the isDisabled shortcut property to check for disabled fieldset ancestors return elem.isDisabled === disabled || // Where there is no isDisabled, check manually /* jshint -W018 */ elem.isDisabled !== !disabled && disabledAncestor( elem ) === disabled; } return elem.disabled === disabled; // Try to winnow out elements that can't be disabled before trusting the disabled property. // Some victims get caught in our net (label, legend, menu, track), but it shouldn't // even exist on them, let alone have a boolean value. } else if ( "label" in elem ) { return elem.disabled === disabled; } // Remaining elements are neither :enabled nor :disabled return false; }; } /** * Returns a function to use in pseudos for positionals * @param {Function} fn */ function createPositionalPseudo( fn ) { return markFunction(function( argument ) { argument = +argument; return markFunction(function( seed, matches ) { var j, matchIndexes = fn( [], seed.length, argument ), i = matchIndexes.length; // Match elements found at the specified indexes while ( i-- ) { if ( seed[ (j = matchIndexes[i]) ] ) { seed[j] = !(matches[j] = seed[j]); } } }); }); } /** * Checks a node for validity as a Sizzle context * @param {Element|Object=} context * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value */ function testContext( context ) { return context && typeof context.getElementsByTagName !== "undefined" && context; } // Expose support vars for convenience support = Sizzle.support = {}; /** * Detects XML nodes * @param {Element|Object} elem An element or a document * @returns {Boolean} True iff elem is a non-HTML XML node */ isXML = Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = elem && (elem.ownerDocument || elem).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; /** * Sets document-related variables once based on the current document * @param {Element|Object} [doc] An element or document object to use to set the document * @returns {Object} Returns the current document */ setDocument = Sizzle.setDocument = function( node ) { var hasCompare, subWindow, doc = node ? node.ownerDocument || node : preferredDoc; // Return early if doc is invalid or already selected if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { return document; } // Update global variables document = doc; docElem = document.documentElement; documentIsHTML = !isXML( document ); // Support: IE 9-11, Edge // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) if ( preferredDoc !== document && (subWindow = document.defaultView) && subWindow.top !== subWindow ) { // Support: IE 11, Edge if ( subWindow.addEventListener ) { subWindow.addEventListener( "unload", unloadHandler, false ); // Support: IE 9 - 10 only } else if ( subWindow.attachEvent ) { subWindow.attachEvent( "onunload", unloadHandler ); } } /* Attributes ---------------------------------------------------------------------- */ // Support: IE<8 // Verify that getAttribute really returns attributes and not properties // (excepting IE8 booleans) support.attributes = assert(function( el ) { el.className = "i"; return !el.getAttribute("className"); }); /* getElement(s)By* ---------------------------------------------------------------------- */ // Check if getElementsByTagName("*") returns only elements support.getElementsByTagName = assert(function( el ) { el.appendChild( document.createComment("") ); return !el.getElementsByTagName("*").length; }); // Support: IE<9 support.getElementsByClassName = rnative.test( document.getElementsByClassName ); // Support: IE<10 // Check if getElementById returns elements by name // The broken getElementById methods don't pick up programmatically-set names, // so use a roundabout getElementsByName test support.getById = assert(function( el ) { docElem.appendChild( el ).id = expando; return !document.getElementsByName || !document.getElementsByName( expando ).length; }); // ID filter and find if ( support.getById ) { Expr.filter["ID"] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { return elem.getAttribute("id") === attrId; }; }; Expr.find["ID"] = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var elem = context.getElementById( id ); return elem ? [ elem ] : []; } }; } else { Expr.filter["ID"] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return node && node.value === attrId; }; }; // Support: IE 6 - 7 only // getElementById is not reliable as a find shortcut Expr.find["ID"] = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var node, i, elems, elem = context.getElementById( id ); if ( elem ) { // Verify the id attribute node = elem.getAttributeNode("id"); if ( node && node.value === id ) { return [ elem ]; } // Fall back on getElementsByName elems = context.getElementsByName( id ); i = 0; while ( (elem = elems[i++]) ) { node = elem.getAttributeNode("id"); if ( node && node.value === id ) { return [ elem ]; } } } return []; } }; } // Tag Expr.find["TAG"] = support.getElementsByTagName ? function( tag, context ) { if ( typeof context.getElementsByTagName !== "undefined" ) { return context.getElementsByTagName( tag ); // DocumentFragment nodes don't have gEBTN } else if ( support.qsa ) { return context.querySelectorAll( tag ); } } : function( tag, context ) { var elem, tmp = [], i = 0, // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too results = context.getElementsByTagName( tag ); // Filter out possible comments if ( tag === "*" ) { while ( (elem = results[i++]) ) { if ( elem.nodeType === 1 ) { tmp.push( elem ); } } return tmp; } return results; }; // Class Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { return context.getElementsByClassName( className ); } }; /* QSA/matchesSelector ---------------------------------------------------------------------- */ // QSA and matchesSelector support // matchesSelector(:active) reports false when true (IE9/Opera 11.5) rbuggyMatches = []; // qSa(:focus) reports false when true (Chrome 21) // We allow this because of a bug in IE8/9 that throws an error // whenever `document.activeElement` is accessed on an iframe // So, we allow :focus to pass through QSA all the time to avoid the IE error // See https://bugs.jquery.com/ticket/13378 rbuggyQSA = []; if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { // Build QSA regex // Regex strategy adopted from Diego Perini assert(function( el ) { // Select is set to empty string on purpose // This is to test IE's treatment of not explicitly // setting a boolean content attribute, // since its presence should be enough // https://bugs.jquery.com/ticket/12359 docElem.appendChild( el ).innerHTML = "" + ""; // Support: IE8, Opera 11-12.16 // Nothing should be selected when empty strings follow ^= or $= or *= // The test attribute must be unknown in Opera but "safe" for WinRT // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section if ( el.querySelectorAll("[msallowcapture^='']").length ) { rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); } // Support: IE8 // Boolean attributes and "value" are not treated correctly if ( !el.querySelectorAll("[selected]").length ) { rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); } // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { rbuggyQSA.push("~="); } // Webkit/Opera - :checked should return selected option elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked // IE8 throws error here and will not see later tests if ( !el.querySelectorAll(":checked").length ) { rbuggyQSA.push(":checked"); } // Support: Safari 8+, iOS 8+ // https://bugs.webkit.org/show_bug.cgi?id=136851 // In-page `selector#id sibling-combinator selector` fails if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { rbuggyQSA.push(".#.+[+~]"); } }); assert(function( el ) { el.innerHTML = "" + ""; // Support: Windows 8 Native Apps // The type and name attributes are restricted during .innerHTML assignment var input = document.createElement("input"); input.setAttribute( "type", "hidden" ); el.appendChild( input ).setAttribute( "name", "D" ); // Support: IE8 // Enforce case-sensitivity of name attribute if ( el.querySelectorAll("[name=d]").length ) { rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); } // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) // IE8 throws error here and will not see later tests if ( el.querySelectorAll(":enabled").length !== 2 ) { rbuggyQSA.push( ":enabled", ":disabled" ); } // Support: IE9-11+ // IE's :disabled selector does not pick up the children of disabled fieldsets docElem.appendChild( el ).disabled = true; if ( el.querySelectorAll(":disabled").length !== 2 ) { rbuggyQSA.push( ":enabled", ":disabled" ); } // Opera 10-11 does not throw on post-comma invalid pseudos el.querySelectorAll("*,:x"); rbuggyQSA.push(",.*:"); }); } if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector) )) ) { assert(function( el ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9) support.disconnectedMatch = matches.call( el, "*" ); // This should fail with an exception // Gecko does not error, returns false instead matches.call( el, "[s!='']:x" ); rbuggyMatches.push( "!=", pseudos ); }); } rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); /* Contains ---------------------------------------------------------------------- */ hasCompare = rnative.test( docElem.compareDocumentPosition ); // Element contains another // Purposefully self-exclusive // As in, an element does not contain itself contains = hasCompare || rnative.test( docElem.contains ) ? function( a, b ) { var adown = a.nodeType === 9 ? a.documentElement : a, bup = b && b.parentNode; return a === bup || !!( bup && bup.nodeType === 1 && ( adown.contains ? adown.contains( bup ) : a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 )); } : function( a, b ) { if ( b ) { while ( (b = b.parentNode) ) { if ( b === a ) { return true; } } } return false; }; /* Sorting ---------------------------------------------------------------------- */ // Document order sorting sortOrder = hasCompare ? function( a, b ) { // Flag for duplicate removal if ( a === b ) { hasDuplicate = true; return 0; } // Sort on method existence if only one input has compareDocumentPosition var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; if ( compare ) { return compare; } // Calculate position if both inputs belong to the same document compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? a.compareDocumentPosition( b ) : // Otherwise we know they are disconnected 1; // Disconnected nodes if ( compare & 1 || (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { // Choose the first element that is related to our preferred document if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { return -1; } if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { return 1; } // Maintain original order return sortInput ? ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 0; } return compare & 4 ? -1 : 1; } : function( a, b ) { // Exit early if the nodes are identical if ( a === b ) { hasDuplicate = true; return 0; } var cur, i = 0, aup = a.parentNode, bup = b.parentNode, ap = [ a ], bp = [ b ]; // Parentless nodes are either documents or disconnected if ( !aup || !bup ) { return a === document ? -1 : b === document ? 1 : aup ? -1 : bup ? 1 : sortInput ? ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 0; // If the nodes are siblings, we can do a quick check } else if ( aup === bup ) { return siblingCheck( a, b ); } // Otherwise we need full lists of their ancestors for comparison cur = a; while ( (cur = cur.parentNode) ) { ap.unshift( cur ); } cur = b; while ( (cur = cur.parentNode) ) { bp.unshift( cur ); } // Walk down the tree looking for a discrepancy while ( ap[i] === bp[i] ) { i++; } return i ? // Do a sibling check if the nodes have a common ancestor siblingCheck( ap[i], bp[i] ) : // Otherwise nodes in our document sort first ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0; }; return document; }; Sizzle.matches = function( expr, elements ) { return Sizzle( expr, null, null, elements ); }; Sizzle.matchesSelector = function( elem, expr ) { // Set document vars if needed if ( ( elem.ownerDocument || elem ) !== document ) { setDocument( elem ); } // Make sure that attribute selectors are quoted expr = expr.replace( rattributeQuotes, "='$1']" ); if ( support.matchesSelector && documentIsHTML && !compilerCache[ expr + " " ] && ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { try { var ret = matches.call( elem, expr ); // IE 9's matchesSelector returns false on disconnected nodes if ( ret || support.disconnectedMatch || // As well, disconnected nodes are said to be in a document // fragment in IE 9 elem.document && elem.document.nodeType !== 11 ) { return ret; } } catch (e) {} } return Sizzle( expr, document, null, [ elem ] ).length > 0; }; Sizzle.contains = function( context, elem ) { // Set document vars if needed if ( ( context.ownerDocument || context ) !== document ) { setDocument( context ); } return contains( context, elem ); }; Sizzle.attr = function( elem, name ) { // Set document vars if needed if ( ( elem.ownerDocument || elem ) !== document ) { setDocument( elem ); } var fn = Expr.attrHandle[ name.toLowerCase() ], // Don't get fooled by Object.prototype properties (jQuery #13807) val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? fn( elem, name, !documentIsHTML ) : undefined; return val !== undefined ? val : support.attributes || !documentIsHTML ? elem.getAttribute( name ) : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null; }; Sizzle.escape = function( sel ) { return (sel + "").replace( rcssescape, fcssescape ); }; Sizzle.error = function( msg ) { throw new Error( "Syntax error, unrecognized expression: " + msg ); }; /** * Document sorting and removing duplicates * @param {ArrayLike} results */ Sizzle.uniqueSort = function( results ) { var elem, duplicates = [], j = 0, i = 0; // Unless we *know* we can detect duplicates, assume their presence hasDuplicate = !support.detectDuplicates; sortInput = !support.sortStable && results.slice( 0 ); results.sort( sortOrder ); if ( hasDuplicate ) { while ( (elem = results[i++]) ) { if ( elem === results[ i ] ) { j = duplicates.push( i ); } } while ( j-- ) { results.splice( duplicates[ j ], 1 ); } } // Clear input after sorting to release objects // See https://github.com/jquery/sizzle/pull/225 sortInput = null; return results; }; /** * Utility function for retrieving the text value of an array of DOM nodes * @param {Array|Element} elem */ getText = Sizzle.getText = function( elem ) { var node, ret = "", i = 0, nodeType = elem.nodeType; if ( !nodeType ) { // If no nodeType, this is expected to be an array while ( (node = elem[i++]) ) { // Do not traverse comment nodes ret += getText( node ); } } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { // Use textContent for elements // innerText usage removed for consistency of new lines (jQuery #11153) if ( typeof elem.textContent === "string" ) { return elem.textContent; } else { // Traverse its children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { ret += getText( elem ); } } } else if ( nodeType === 3 || nodeType === 4 ) { return elem.nodeValue; } // Do not include comment or processing instruction nodes return ret; }; Expr = Sizzle.selectors = { // Can be adjusted by the user cacheLength: 50, createPseudo: markFunction, match: matchExpr, attrHandle: {}, find: {}, relative: { ">": { dir: "parentNode", first: true }, " ": { dir: "parentNode" }, "+": { dir: "previousSibling", first: true }, "~": { dir: "previousSibling" } }, preFilter: { "ATTR": function( match ) { match[1] = match[1].replace( runescape, funescape ); // Move the given value to match[3] whether quoted or unquoted match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); if ( match[2] === "~=" ) { match[3] = " " + match[3] + " "; } return match.slice( 0, 4 ); }, "CHILD": function( match ) { /* matches from matchExpr["CHILD"] 1 type (only|nth|...) 2 what (child|of-type) 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 4 xn-component of xn+y argument ([+-]?\d*n|) 5 sign of xn-component 6 x of xn-component 7 sign of y-component 8 y of y-component */ match[1] = match[1].toLowerCase(); if ( match[1].slice( 0, 3 ) === "nth" ) { // nth-* requires argument if ( !match[3] ) { Sizzle.error( match[0] ); } // numeric x and y parameters for Expr.filter.CHILD // remember that false/true cast respectively to 0/1 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); // other types prohibit arguments } else if ( match[3] ) { Sizzle.error( match[0] ); } return match; }, "PSEUDO": function( match ) { var excess, unquoted = !match[6] && match[2]; if ( matchExpr["CHILD"].test( match[0] ) ) { return null; } // Accept quoted arguments as-is if ( match[3] ) { match[2] = match[4] || match[5] || ""; // Strip excess characters from unquoted arguments } else if ( unquoted && rpseudo.test( unquoted ) && // Get excess from tokenize (recursively) (excess = tokenize( unquoted, true )) && // advance to the next closing parenthesis (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { // excess is a negative index match[0] = match[0].slice( 0, excess ); match[2] = unquoted.slice( 0, excess ); } // Return only captures needed by the pseudo filter method (type and argument) return match.slice( 0, 3 ); } }, filter: { "TAG": function( nodeNameSelector ) { var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); return nodeNameSelector === "*" ? function() { return true; } : function( elem ) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; }; }, "CLASS": function( className ) { var pattern = classCache[ className + " " ]; return pattern || (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && classCache( className, function( elem ) { return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); }); }, "ATTR": function( name, operator, check ) { return function( elem ) { var result = Sizzle.attr( elem, name ); if ( result == null ) { return operator === "!="; } if ( !operator ) { return true; } result += ""; return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf( check ) === 0 : operator === "*=" ? check && result.indexOf( check ) > -1 : operator === "$=" ? check && result.slice( -check.length ) === check : operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : false; }; }, "CHILD": function( type, what, argument, first, last ) { var simple = type.slice( 0, 3 ) !== "nth", forward = type.slice( -4 ) !== "last", ofType = what === "of-type"; return first === 1 && last === 0 ? // Shortcut for :nth-*(n) function( elem ) { return !!elem.parentNode; } : function( elem, context, xml ) { var cache, uniqueCache, outerCache, node, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType, diff = false; if ( parent ) { // :(first|last|only)-(child|of-type) if ( simple ) { while ( dir ) { node = elem; while ( (node = node[ dir ]) ) { if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { return false; } } // Reverse direction for :only-* (if we haven't yet done so) start = dir = type === "only" && !start && "nextSibling"; } return true; } start = [ forward ? parent.firstChild : parent.lastChild ]; // non-xml :nth-child(...) stores cache data on `parent` if ( forward && useCache ) { // Seek `elem` from a previously-cached index // ...in a gzip-friendly way node = parent; outerCache = node[ expando ] || (node[ expando ] = {}); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || (outerCache[ node.uniqueID ] = {}); cache = uniqueCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; diff = nodeIndex && cache[ 2 ]; node = nodeIndex && parent.childNodes[ nodeIndex ]; while ( (node = ++nodeIndex && node && node[ dir ] || // Fallback to seeking `elem` from the start (diff = nodeIndex = 0) || start.pop()) ) { // When found, cache indexes on `parent` and break if ( node.nodeType === 1 && ++diff && node === elem ) { uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; break; } } } else { // Use previously-cached element index if available if ( useCache ) { // ...in a gzip-friendly way node = elem; outerCache = node[ expando ] || (node[ expando ] = {}); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || (outerCache[ node.uniqueID ] = {}); cache = uniqueCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; diff = nodeIndex; } // xml :nth-child(...) // or :nth-last-child(...) or :nth(-last)?-of-type(...) if ( diff === false ) { // Use the same loop as above to seek `elem` from the start while ( (node = ++nodeIndex && node && node[ dir ] || (diff = nodeIndex = 0) || start.pop()) ) { if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { // Cache the index of each encountered element if ( useCache ) { outerCache = node[ expando ] || (node[ expando ] = {}); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || (outerCache[ node.uniqueID ] = {}); uniqueCache[ type ] = [ dirruns, diff ]; } if ( node === elem ) { break; } } } } } // Incorporate the offset, then check against cycle size diff -= last; return diff === first || ( diff % first === 0 && diff / first >= 0 ); } }; }, "PSEUDO": function( pseudo, argument ) { // pseudo-class names are case-insensitive // http://www.w3.org/TR/selectors/#pseudo-classes // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters // Remember that setFilters inherits from pseudos var args, fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || Sizzle.error( "unsupported pseudo: " + pseudo ); // The user may use createPseudo to indicate that // arguments are needed to create the filter function // just as Sizzle does if ( fn[ expando ] ) { return fn( argument ); } // But maintain support for old signatures if ( fn.length > 1 ) { args = [ pseudo, pseudo, "", argument ]; return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? markFunction(function( seed, matches ) { var idx, matched = fn( seed, argument ), i = matched.length; while ( i-- ) { idx = indexOf( seed, matched[i] ); seed[ idx ] = !( matches[ idx ] = matched[i] ); } }) : function( elem ) { return fn( elem, 0, args ); }; } return fn; } }, pseudos: { // Potentially complex pseudos "not": markFunction(function( selector ) { // Trim the selector passed to compile // to avoid treating leading and trailing // spaces as combinators var input = [], results = [], matcher = compile( selector.replace( rtrim, "$1" ) ); return matcher[ expando ] ? markFunction(function( seed, matches, context, xml ) { var elem, unmatched = matcher( seed, null, xml, [] ), i = seed.length; // Match elements unmatched by `matcher` while ( i-- ) { if ( (elem = unmatched[i]) ) { seed[i] = !(matches[i] = elem); } } }) : function( elem, context, xml ) { input[0] = elem; matcher( input, null, xml, results ); // Don't keep the element (issue #299) input[0] = null; return !results.pop(); }; }), "has": markFunction(function( selector ) { return function( elem ) { return Sizzle( selector, elem ).length > 0; }; }), "contains": markFunction(function( text ) { text = text.replace( runescape, funescape ); return function( elem ) { return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; }; }), // "Whether an element is represented by a :lang() selector // is based solely on the element's language value // being equal to the identifier C, // or beginning with the identifier C immediately followed by "-". // The matching of C against the element's language value is performed case-insensitively. // The identifier C does not have to be a valid language name." // http://www.w3.org/TR/selectors/#lang-pseudo "lang": markFunction( function( lang ) { // lang value must be a valid identifier if ( !ridentifier.test(lang || "") ) { Sizzle.error( "unsupported lang: " + lang ); } lang = lang.replace( runescape, funescape ).toLowerCase(); return function( elem ) { var elemLang; do { if ( (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { elemLang = elemLang.toLowerCase(); return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; } } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); return false; }; }), // Miscellaneous "target": function( elem ) { var hash = window.location && window.location.hash; return hash && hash.slice( 1 ) === elem.id; }, "root": function( elem ) { return elem === docElem; }, "focus": function( elem ) { return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); }, // Boolean properties "enabled": createDisabledPseudo( false ), "disabled": createDisabledPseudo( true ), "checked": function( elem ) { // In CSS3, :checked should return both checked and selected elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked var nodeName = elem.nodeName.toLowerCase(); return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); }, "selected": function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } return elem.selected === true; }, // Contents "empty": function( elem ) { // http://www.w3.org/TR/selectors/#empty-pseudo // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), // but not by others (comment: 8; processing instruction: 7; etc.) // nodeType < 6 works because attributes (2) do not appear as children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { if ( elem.nodeType < 6 ) { return false; } } return true; }, "parent": function( elem ) { return !Expr.pseudos["empty"]( elem ); }, // Element/input types "header": function( elem ) { return rheader.test( elem.nodeName ); }, "input": function( elem ) { return rinputs.test( elem.nodeName ); }, "button": function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === "button" || name === "button"; }, "text": function( elem ) { var attr; return elem.nodeName.toLowerCase() === "input" && elem.type === "text" && // Support: IE<8 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); }, // Position-in-collection "first": createPositionalPseudo(function() { return [ 0 ]; }), "last": createPositionalPseudo(function( matchIndexes, length ) { return [ length - 1 ]; }), "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { return [ argument < 0 ? argument + length : argument ]; }), "even": createPositionalPseudo(function( matchIndexes, length ) { var i = 0; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; }), "odd": createPositionalPseudo(function( matchIndexes, length ) { var i = 1; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; }), "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; --i >= 0; ) { matchIndexes.push( i ); } return matchIndexes; }), "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; ++i < length; ) { matchIndexes.push( i ); } return matchIndexes; }) } }; Expr.pseudos["nth"] = Expr.pseudos["eq"]; // Add button/input type pseudos for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { Expr.pseudos[ i ] = createInputPseudo( i ); } for ( i in { submit: true, reset: true } ) { Expr.pseudos[ i ] = createButtonPseudo( i ); } // Easy API for creating new setFilters function setFilters() {} setFilters.prototype = Expr.filters = Expr.pseudos; Expr.setFilters = new setFilters(); tokenize = Sizzle.tokenize = function( selector, parseOnly ) { var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[ selector + " " ]; if ( cached ) { return parseOnly ? 0 : cached.slice( 0 ); } soFar = selector; groups = []; preFilters = Expr.preFilter; while ( soFar ) { // Comma and first run if ( !matched || (match = rcomma.exec( soFar )) ) { if ( match ) { // Don't consume trailing commas as valid soFar = soFar.slice( match[0].length ) || soFar; } groups.push( (tokens = []) ); } matched = false; // Combinators if ( (match = rcombinators.exec( soFar )) ) { matched = match.shift(); tokens.push({ value: matched, // Cast descendant combinators to space type: match[0].replace( rtrim, " " ) }); soFar = soFar.slice( matched.length ); } // Filters for ( type in Expr.filter ) { if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || (match = preFilters[ type ]( match ))) ) { matched = match.shift(); tokens.push({ value: matched, type: type, matches: match }); soFar = soFar.slice( matched.length ); } } if ( !matched ) { break; } } // Return the length of the invalid excess // if we're just parsing // Otherwise, throw an error or return tokens return parseOnly ? soFar.length : soFar ? Sizzle.error( selector ) : // Cache the tokens tokenCache( selector, groups ).slice( 0 ); }; function toSelector( tokens ) { var i = 0, len = tokens.length, selector = ""; for ( ; i < len; i++ ) { selector += tokens[i].value; } return selector; } function addCombinator( matcher, combinator, base ) { var dir = combinator.dir, skip = combinator.next, key = skip || dir, checkNonElements = base && key === "parentNode", doneName = done++; return combinator.first ? // Check against closest ancestor/preceding element function( elem, context, xml ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { return matcher( elem, context, xml ); } } return false; } : // Check against all ancestor/preceding elements function( elem, context, xml ) { var oldCache, uniqueCache, outerCache, newCache = [ dirruns, doneName ]; // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching if ( xml ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { if ( matcher( elem, context, xml ) ) { return true; } } } } else { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { outerCache = elem[ expando ] || (elem[ expando ] = {}); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); if ( skip && skip === elem.nodeName.toLowerCase() ) { elem = elem[ dir ] || elem; } else if ( (oldCache = uniqueCache[ key ]) && oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { // Assign to newCache so results back-propagate to previous elements return (newCache[ 2 ] = oldCache[ 2 ]); } else { // Reuse newcache so results back-propagate to previous elements uniqueCache[ key ] = newCache; // A match means we're done; a fail means we have to keep checking if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { return true; } } } } } return false; }; } function elementMatcher( matchers ) { return matchers.length > 1 ? function( elem, context, xml ) { var i = matchers.length; while ( i-- ) { if ( !matchers[i]( elem, context, xml ) ) { return false; } } return true; } : matchers[0]; } function multipleContexts( selector, contexts, results ) { var i = 0, len = contexts.length; for ( ; i < len; i++ ) { Sizzle( selector, contexts[i], results ); } return results; } function condense( unmatched, map, filter, context, xml ) { var elem, newUnmatched = [], i = 0, len = unmatched.length, mapped = map != null; for ( ; i < len; i++ ) { if ( (elem = unmatched[i]) ) { if ( !filter || filter( elem, context, xml ) ) { newUnmatched.push( elem ); if ( mapped ) { map.push( i ); } } } } return newUnmatched; } function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { if ( postFilter && !postFilter[ expando ] ) { postFilter = setMatcher( postFilter ); } if ( postFinder && !postFinder[ expando ] ) { postFinder = setMatcher( postFinder, postSelector ); } return markFunction(function( seed, results, context, xml ) { var temp, i, elem, preMap = [], postMap = [], preexisting = results.length, // Get initial elements from seed or context elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), // Prefilter to get matcher input, preserving a map for seed-results synchronization matcherIn = preFilter && ( seed || !selector ) ? condense( elems, preMap, preFilter, context, xml ) : elems, matcherOut = matcher ? // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, postFinder || ( seed ? preFilter : preexisting || postFilter ) ? // ...intermediate processing is necessary [] : // ...otherwise use results directly results : matcherIn; // Find primary matches if ( matcher ) { matcher( matcherIn, matcherOut, context, xml ); } // Apply postFilter if ( postFilter ) { temp = condense( matcherOut, postMap ); postFilter( temp, [], context, xml ); // Un-match failing elements by moving them back to matcherIn i = temp.length; while ( i-- ) { if ( (elem = temp[i]) ) { matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); } } } if ( seed ) { if ( postFinder || preFilter ) { if ( postFinder ) { // Get the final matcherOut by condensing this intermediate into postFinder contexts temp = []; i = matcherOut.length; while ( i-- ) { if ( (elem = matcherOut[i]) ) { // Restore matcherIn since elem is not yet a final match temp.push( (matcherIn[i] = elem) ); } } postFinder( null, (matcherOut = []), temp, xml ); } // Move matched elements from seed to results to keep them synchronized i = matcherOut.length; while ( i-- ) { if ( (elem = matcherOut[i]) && (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { seed[temp] = !(results[temp] = elem); } } } // Add elements to results, through postFinder if defined } else { matcherOut = condense( matcherOut === results ? matcherOut.splice( preexisting, matcherOut.length ) : matcherOut ); if ( postFinder ) { postFinder( null, results, matcherOut, xml ); } else { push.apply( results, matcherOut ); } } }); } function matcherFromTokens( tokens ) { var checkContext, matcher, j, len = tokens.length, leadingRelative = Expr.relative[ tokens[0].type ], implicitRelative = leadingRelative || Expr.relative[" "], i = leadingRelative ? 1 : 0, // The foundational matcher ensures that elements are reachable from top-level context(s) matchContext = addCombinator( function( elem ) { return elem === checkContext; }, implicitRelative, true ), matchAnyContext = addCombinator( function( elem ) { return indexOf( checkContext, elem ) > -1; }, implicitRelative, true ), matchers = [ function( elem, context, xml ) { var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( (checkContext = context).nodeType ? matchContext( elem, context, xml ) : matchAnyContext( elem, context, xml ) ); // Avoid hanging onto element (issue #299) checkContext = null; return ret; } ]; for ( ; i < len; i++ ) { if ( (matcher = Expr.relative[ tokens[i].type ]) ) { matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; } else { matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); // Return special upon seeing a positional matcher if ( matcher[ expando ] ) { // Find the next relative operator (if any) for proper handling j = ++i; for ( ; j < len; j++ ) { if ( Expr.relative[ tokens[j].type ] ) { break; } } return setMatcher( i > 1 && elementMatcher( matchers ), i > 1 && toSelector( // If the preceding token was a descendant combinator, insert an implicit any-element `*` tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) ).replace( rtrim, "$1" ), matcher, i < j && matcherFromTokens( tokens.slice( i, j ) ), j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), j < len && toSelector( tokens ) ); } matchers.push( matcher ); } } return elementMatcher( matchers ); } function matcherFromGroupMatchers( elementMatchers, setMatchers ) { var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function( seed, context, xml, results, outermost ) { var elem, j, matcher, matchedCount = 0, i = "0", unmatched = seed && [], setMatched = [], contextBackup = outermostContext, // We must always have either seed elements or outermost context elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), // Use integer dirruns iff this is the outermost matcher dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), len = elems.length; if ( outermost ) { outermostContext = context === document || context || outermost; } // Add elements passing elementMatchers directly to results // Support: IE<9, Safari // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id for ( ; i !== len && (elem = elems[i]) != null; i++ ) { if ( byElement && elem ) { j = 0; if ( !context && elem.ownerDocument !== document ) { setDocument( elem ); xml = !documentIsHTML; } while ( (matcher = elementMatchers[j++]) ) { if ( matcher( elem, context || document, xml) ) { results.push( elem ); break; } } if ( outermost ) { dirruns = dirrunsUnique; } } // Track unmatched elements for set filters if ( bySet ) { // They will have gone through all possible matchers if ( (elem = !matcher && elem) ) { matchedCount--; } // Lengthen the array for every element, matched or not if ( seed ) { unmatched.push( elem ); } } } // `i` is now the count of elements visited above, and adding it to `matchedCount` // makes the latter nonnegative. matchedCount += i; // Apply set filters to unmatched elements // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` // equals `i`), unless we didn't visit _any_ elements in the above loop because we have // no element matchers and no seed. // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that // case, which will result in a "00" `matchedCount` that differs from `i` but is also // numerically zero. if ( bySet && i !== matchedCount ) { j = 0; while ( (matcher = setMatchers[j++]) ) { matcher( unmatched, setMatched, context, xml ); } if ( seed ) { // Reintegrate element matches to eliminate the need for sorting if ( matchedCount > 0 ) { while ( i-- ) { if ( !(unmatched[i] || setMatched[i]) ) { setMatched[i] = pop.call( results ); } } } // Discard index placeholder values to get only actual matches setMatched = condense( setMatched ); } // Add matches to results push.apply( results, setMatched ); // Seedless set matches succeeding multiple successful matchers stipulate sorting if ( outermost && !seed && setMatched.length > 0 && ( matchedCount + setMatchers.length ) > 1 ) { Sizzle.uniqueSort( results ); } } // Override manipulation of globals by nested matchers if ( outermost ) { dirruns = dirrunsUnique; outermostContext = contextBackup; } return unmatched; }; return bySet ? markFunction( superMatcher ) : superMatcher; } compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { var i, setMatchers = [], elementMatchers = [], cached = compilerCache[ selector + " " ]; if ( !cached ) { // Generate a function of recursive functions that can be used to check each element if ( !match ) { match = tokenize( selector ); } i = match.length; while ( i-- ) { cached = matcherFromTokens( match[i] ); if ( cached[ expando ] ) { setMatchers.push( cached ); } else { elementMatchers.push( cached ); } } // Cache the compiled function cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); // Save selector and tokenization cached.selector = selector; } return cached; }; /** * A low-level selection function that works with Sizzle's compiled * selector functions * @param {String|Function} selector A selector or a pre-compiled * selector function built with Sizzle.compile * @param {Element} context * @param {Array} [results] * @param {Array} [seed] A set of elements to match against */ select = Sizzle.select = function( selector, context, results, seed ) { var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, match = !seed && tokenize( (selector = compiled.selector || selector) ); results = results || []; // Try to minimize operations if there is only one selector in the list and no seed // (the latter of which guarantees us context) if ( match.length === 1 ) { // Reduce context if the leading compound selector is an ID tokens = match[0] = match[0].slice( 0 ); if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; if ( !context ) { return results; // Precompiled matchers will still verify ancestry, so step up a level } else if ( compiled ) { context = context.parentNode; } selector = selector.slice( tokens.shift().value.length ); } // Fetch a seed set for right-to-left matching i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; while ( i-- ) { token = tokens[i]; // Abort if we hit a combinator if ( Expr.relative[ (type = token.type) ] ) { break; } if ( (find = Expr.find[ type ]) ) { // Search, expanding context for leading sibling combinators if ( (seed = find( token.matches[0].replace( runescape, funescape ), rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context )) ) { // If seed is empty or no tokens remain, we can return early tokens.splice( i, 1 ); selector = seed.length && toSelector( tokens ); if ( !selector ) { push.apply( results, seed ); return results; } break; } } } } // Compile and execute a filtering function if one is not provided // Provide `match` to avoid retokenization if we modified the selector above ( compiled || compile( selector, match ) )( seed, context, !documentIsHTML, results, !context || rsibling.test( selector ) && testContext( context.parentNode ) || context ); return results; }; // One-time assignments // Sort stability support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; // Support: Chrome 14-35+ // Always assume duplicates if they aren't passed to the comparison function support.detectDuplicates = !!hasDuplicate; // Initialize against the default document setDocument(); // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) // Detached nodes confoundingly follow *each other* support.sortDetached = assert(function( el ) { // Should return 1, but returns 4 (following) return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; }); // Support: IE<8 // Prevent attribute/property "interpolation" // https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx if ( !assert(function( el ) { el.innerHTML = ""; return el.firstChild.getAttribute("href") === "#" ; }) ) { addHandle( "type|href|height|width", function( elem, name, isXML ) { if ( !isXML ) { return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); } }); } // Support: IE<9 // Use defaultValue in place of getAttribute("value") if ( !support.attributes || !assert(function( el ) { el.innerHTML = ""; el.firstChild.setAttribute( "value", "" ); return el.firstChild.getAttribute( "value" ) === ""; }) ) { addHandle( "value", function( elem, name, isXML ) { if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { return elem.defaultValue; } }); } // Support: IE<9 // Use getAttributeNode to fetch booleans when getAttribute lies if ( !assert(function( el ) { return el.getAttribute("disabled") == null; }) ) { addHandle( booleans, function( elem, name, isXML ) { var val; if ( !isXML ) { return elem[ name ] === true ? name.toLowerCase() : (val = elem.getAttributeNode( name )) && val.specified ? val.value : null; } }); } return Sizzle; })( window ); jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; // Deprecated jQuery.expr[ ":" ] = jQuery.expr.pseudos; jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; jQuery.text = Sizzle.getText; jQuery.isXMLDoc = Sizzle.isXML; jQuery.contains = Sizzle.contains; jQuery.escapeSelector = Sizzle.escape; var dir = function( elem, dir, until ) { var matched = [], truncate = until !== undefined; while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { if ( elem.nodeType === 1 ) { if ( truncate && jQuery( elem ).is( until ) ) { break; } matched.push( elem ); } } return matched; }; var siblings = function( n, elem ) { var matched = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { matched.push( n ); } } return matched; }; var rneedsContext = jQuery.expr.match.needsContext; function nodeName( elem, name ) { return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); }; var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); var risSimple = /^.[^:#\[\.,]*$/; // Implement the identical functionality for filter and not function winnow( elements, qualifier, not ) { if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep( elements, function( elem, i ) { return !!qualifier.call( elem, i, elem ) !== not; } ); } // Single element if ( qualifier.nodeType ) { return jQuery.grep( elements, function( elem ) { return ( elem === qualifier ) !== not; } ); } // Arraylike of elements (jQuery, arguments, Array) if ( typeof qualifier !== "string" ) { return jQuery.grep( elements, function( elem ) { return ( indexOf.call( qualifier, elem ) > -1 ) !== not; } ); } // Simple selector that can be filtered directly, removing non-Elements if ( risSimple.test( qualifier ) ) { return jQuery.filter( qualifier, elements, not ); } // Complex selector, compare the two sets, removing non-Elements qualifier = jQuery.filter( qualifier, elements ); return jQuery.grep( elements, function( elem ) { return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; } ); } jQuery.filter = function( expr, elems, not ) { var elem = elems[ 0 ]; if ( not ) { expr = ":not(" + expr + ")"; } if ( elems.length === 1 && elem.nodeType === 1 ) { return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; } return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { return elem.nodeType === 1; } ) ); }; jQuery.fn.extend( { find: function( selector ) { var i, ret, len = this.length, self = this; if ( typeof selector !== "string" ) { return this.pushStack( jQuery( selector ).filter( function() { for ( i = 0; i < len; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } } ) ); } ret = this.pushStack( [] ); for ( i = 0; i < len; i++ ) { jQuery.find( selector, self[ i ], ret ); } return len > 1 ? jQuery.uniqueSort( ret ) : ret; }, filter: function( selector ) { return this.pushStack( winnow( this, selector || [], false ) ); }, not: function( selector ) { return this.pushStack( winnow( this, selector || [], true ) ); }, is: function( selector ) { return !!winnow( this, // If this is a positional/relative selector, check membership in the returned set // so $("p:first").is("p:last") won't return true for a doc with two "p". typeof selector === "string" && rneedsContext.test( selector ) ? jQuery( selector ) : selector || [], false ).length; } } ); // Initialize a jQuery object // A central reference to the root jQuery(document) var rootjQuery, // A simple way to check for HTML strings // Prioritize #id over to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) // Shortcut simple #id case for speed rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, init = jQuery.fn.init = function( selector, context, root ) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if ( !selector ) { return this; } // Method init() accepts an alternate rootjQuery // so migrate can support jQuery.sub (gh-2101) root = root || rootjQuery; // Handle HTML strings if ( typeof selector === "string" ) { if ( selector[ 0 ] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if ( match && ( match[ 1 ] || !context ) ) { // HANDLE: $(html) -> $(array) if ( match[ 1 ] ) { context = context instanceof jQuery ? context[ 0 ] : context; // Option to run scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge( this, jQuery.parseHTML( match[ 1 ], context && context.nodeType ? context.ownerDocument || context : document, true ) ); // HANDLE: $(html, props) if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { for ( match in context ) { // Properties of context are called as methods if possible if ( jQuery.isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes } else { this.attr( match, context[ match ] ); } } } return this; // HANDLE: $(#id) } else { elem = document.getElementById( match[ 2 ] ); if ( elem ) { // Inject the element directly into the jQuery object this[ 0 ] = elem; this.length = 1; } return this; } // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return ( context || root ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(DOMElement) } else if ( selector.nodeType ) { this[ 0 ] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return root.ready !== undefined ? root.ready( selector ) : // Execute immediately if ready is not present selector( jQuery ); } return jQuery.makeArray( selector, this ); }; // Give the init function the jQuery prototype for later instantiation init.prototype = jQuery.fn; // Initialize central reference rootjQuery = jQuery( document ); var rparentsprev = /^(?:parents|prev(?:Until|All))/, // Methods guaranteed to produce a unique set when starting from a unique set guaranteedUnique = { children: true, contents: true, next: true, prev: true }; jQuery.fn.extend( { has: function( target ) { var targets = jQuery( target, this ), l = targets.length; return this.filter( function() { var i = 0; for ( ; i < l; i++ ) { if ( jQuery.contains( this, targets[ i ] ) ) { return true; } } } ); }, closest: function( selectors, context ) { var cur, i = 0, l = this.length, matched = [], targets = typeof selectors !== "string" && jQuery( selectors ); // Positional selectors never match, since there's no _selection_ context if ( !rneedsContext.test( selectors ) ) { for ( ; i < l; i++ ) { for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { // Always skip document fragments if ( cur.nodeType < 11 && ( targets ? targets.index( cur ) > -1 : // Don't pass non-elements to Sizzle cur.nodeType === 1 && jQuery.find.matchesSelector( cur, selectors ) ) ) { matched.push( cur ); break; } } } } return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); }, // Determine the position of an element within the set index: function( elem ) { // No argument, return index in parent if ( !elem ) { return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; } // Index in selector if ( typeof elem === "string" ) { return indexOf.call( jQuery( elem ), this[ 0 ] ); } // Locate the position of the desired element return indexOf.call( this, // If it receives a jQuery object, the first element is used elem.jquery ? elem[ 0 ] : elem ); }, add: function( selector, context ) { return this.pushStack( jQuery.uniqueSort( jQuery.merge( this.get(), jQuery( selector, context ) ) ) ); }, addBack: function( selector ) { return this.add( selector == null ? this.prevObject : this.prevObject.filter( selector ) ); } } ); function sibling( cur, dir ) { while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} return cur; } jQuery.each( { parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return dir( elem, "parentNode", until ); }, next: function( elem ) { return sibling( elem, "nextSibling" ); }, prev: function( elem ) { return sibling( elem, "previousSibling" ); }, nextAll: function( elem ) { return dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return siblings( ( elem.parentNode || {} ).firstChild, elem ); }, children: function( elem ) { return siblings( elem.firstChild ); }, contents: function( elem ) { if ( nodeName( elem, "iframe" ) ) { return elem.contentDocument; } // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only // Treat the template element as a regular one in browsers that // don't support it. if ( nodeName( elem, "template" ) ) { elem = elem.content || elem; } return jQuery.merge( [], elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var matched = jQuery.map( this, fn, until ); if ( name.slice( -5 ) !== "Until" ) { selector = until; } if ( selector && typeof selector === "string" ) { matched = jQuery.filter( selector, matched ); } if ( this.length > 1 ) { // Remove duplicates if ( !guaranteedUnique[ name ] ) { jQuery.uniqueSort( matched ); } // Reverse order for parents* and prev-derivatives if ( rparentsprev.test( name ) ) { matched.reverse(); } } return this.pushStack( matched ); }; } ); var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); // Convert String-formatted options into Object-formatted ones function createOptions( options ) { var object = {}; jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { object[ flag ] = true; } ); return object; } /* * Create a callback list using the following parameters: * * options: an optional list of space-separated options that will change how * the callback list behaves or a more traditional option object * * By default a callback list will act like an event callback list and can be * "fired" multiple times. * * Possible options: * * once: will ensure the callback list can only be fired once (like a Deferred) * * memory: will keep track of previous values and will call any callback added * after the list has been fired right away with the latest "memorized" * values (like a Deferred) * * unique: will ensure a callback can only be added once (no duplicate in the list) * * stopOnFalse: interrupt callings when a callback returns false * */ jQuery.Callbacks = function( options ) { // Convert options from String-formatted to Object-formatted if needed // (we check in cache first) options = typeof options === "string" ? createOptions( options ) : jQuery.extend( {}, options ); var // Flag to know if list is currently firing firing, // Last fire value for non-forgettable lists memory, // Flag to know if list was already fired fired, // Flag to prevent firing locked, // Actual callback list list = [], // Queue of execution data for repeatable lists queue = [], // Index of currently firing callback (modified by add/remove as needed) firingIndex = -1, // Fire callbacks fire = function() { // Enforce single-firing locked = locked || options.once; // Execute callbacks for all pending executions, // respecting firingIndex overrides and runtime changes fired = firing = true; for ( ; queue.length; firingIndex = -1 ) { memory = queue.shift(); while ( ++firingIndex < list.length ) { // Run callback and check for early termination if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && options.stopOnFalse ) { // Jump to end and forget the data so .add doesn't re-fire firingIndex = list.length; memory = false; } } } // Forget the data if we're done with it if ( !options.memory ) { memory = false; } firing = false; // Clean up if we're done firing for good if ( locked ) { // Keep an empty list if we have data for future add calls if ( memory ) { list = []; // Otherwise, this object is spent } else { list = ""; } } }, // Actual Callbacks object self = { // Add a callback or a collection of callbacks to the list add: function() { if ( list ) { // If we have memory from a past run, we should fire after adding if ( memory && !firing ) { firingIndex = list.length - 1; queue.push( memory ); } ( function add( args ) { jQuery.each( args, function( _, arg ) { if ( jQuery.isFunction( arg ) ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { // Inspect recursively add( arg ); } } ); } )( arguments ); if ( memory && !firing ) { fire(); } } return this; }, // Remove a callback from the list remove: function() { jQuery.each( arguments, function( _, arg ) { var index; while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { list.splice( index, 1 ); // Handle firing indexes if ( index <= firingIndex ) { firingIndex--; } } } ); return this; }, // Check if a given callback is in the list. // If no argument is given, return whether or not list has callbacks attached. has: function( fn ) { return fn ? jQuery.inArray( fn, list ) > -1 : list.length > 0; }, // Remove all callbacks from the list empty: function() { if ( list ) { list = []; } return this; }, // Disable .fire and .add // Abort any current/pending executions // Clear all callbacks and values disable: function() { locked = queue = []; list = memory = ""; return this; }, disabled: function() { return !list; }, // Disable .fire // Also disable .add unless we have memory (since it would have no effect) // Abort any pending executions lock: function() { locked = queue = []; if ( !memory && !firing ) { list = memory = ""; } return this; }, locked: function() { return !!locked; }, // Call all callbacks with the given context and arguments fireWith: function( context, args ) { if ( !locked ) { args = args || []; args = [ context, args.slice ? args.slice() : args ]; queue.push( args ); if ( !firing ) { fire(); } } return this; }, // Call all the callbacks with the given arguments fire: function() { self.fireWith( this, arguments ); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!fired; } }; return self; }; function Identity( v ) { return v; } function Thrower( ex ) { throw ex; } function adoptValue( value, resolve, reject, noValue ) { var method; try { // Check for promise aspect first to privilege synchronous behavior if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { method.call( value ).done( resolve ).fail( reject ); // Other thenables } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { method.call( value, resolve, reject ); // Other non-thenables } else { // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: // * false: [ value ].slice( 0 ) => resolve( value ) // * true: [ value ].slice( 1 ) => resolve() resolve.apply( undefined, [ value ].slice( noValue ) ); } // For Promises/A+, convert exceptions into rejections // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in // Deferred#then to conditionally suppress rejection. } catch ( value ) { // Support: Android 4.0 only // Strict mode functions invoked without .call/.apply get global-object context reject.apply( undefined, [ value ] ); } } jQuery.extend( { Deferred: function( func ) { var tuples = [ // action, add listener, callbacks, // ... .then handlers, argument index, [final state] [ "notify", "progress", jQuery.Callbacks( "memory" ), jQuery.Callbacks( "memory" ), 2 ], [ "resolve", "done", jQuery.Callbacks( "once memory" ), jQuery.Callbacks( "once memory" ), 0, "resolved" ], [ "reject", "fail", jQuery.Callbacks( "once memory" ), jQuery.Callbacks( "once memory" ), 1, "rejected" ] ], state = "pending", promise = { state: function() { return state; }, always: function() { deferred.done( arguments ).fail( arguments ); return this; }, "catch": function( fn ) { return promise.then( null, fn ); }, // Keep pipe for back-compat pipe: function( /* fnDone, fnFail, fnProgress */ ) { var fns = arguments; return jQuery.Deferred( function( newDefer ) { jQuery.each( tuples, function( i, tuple ) { // Map tuples (progress, done, fail) to arguments (done, fail, progress) var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; // deferred.progress(function() { bind to newDefer or newDefer.notify }) // deferred.done(function() { bind to newDefer or newDefer.resolve }) // deferred.fail(function() { bind to newDefer or newDefer.reject }) deferred[ tuple[ 1 ] ]( function() { var returned = fn && fn.apply( this, arguments ); if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise() .progress( newDefer.notify ) .done( newDefer.resolve ) .fail( newDefer.reject ); } else { newDefer[ tuple[ 0 ] + "With" ]( this, fn ? [ returned ] : arguments ); } } ); } ); fns = null; } ).promise(); }, then: function( onFulfilled, onRejected, onProgress ) { var maxDepth = 0; function resolve( depth, deferred, handler, special ) { return function() { var that = this, args = arguments, mightThrow = function() { var returned, then; // Support: Promises/A+ section 2.3.3.3.3 // https://promisesaplus.com/#point-59 // Ignore double-resolution attempts if ( depth < maxDepth ) { return; } returned = handler.apply( that, args ); // Support: Promises/A+ section 2.3.1 // https://promisesaplus.com/#point-48 if ( returned === deferred.promise() ) { throw new TypeError( "Thenable self-resolution" ); } // Support: Promises/A+ sections 2.3.3.1, 3.5 // https://promisesaplus.com/#point-54 // https://promisesaplus.com/#point-75 // Retrieve `then` only once then = returned && // Support: Promises/A+ section 2.3.4 // https://promisesaplus.com/#point-64 // Only check objects and functions for thenability ( typeof returned === "object" || typeof returned === "function" ) && returned.then; // Handle a returned thenable if ( jQuery.isFunction( then ) ) { // Special processors (notify) just wait for resolution if ( special ) { then.call( returned, resolve( maxDepth, deferred, Identity, special ), resolve( maxDepth, deferred, Thrower, special ) ); // Normal processors (resolve) also hook into progress } else { // ...and disregard older resolution values maxDepth++; then.call( returned, resolve( maxDepth, deferred, Identity, special ), resolve( maxDepth, deferred, Thrower, special ), resolve( maxDepth, deferred, Identity, deferred.notifyWith ) ); } // Handle all other returned values } else { // Only substitute handlers pass on context // and multiple values (non-spec behavior) if ( handler !== Identity ) { that = undefined; args = [ returned ]; } // Process the value(s) // Default process is resolve ( special || deferred.resolveWith )( that, args ); } }, // Only normal processors (resolve) catch and reject exceptions process = special ? mightThrow : function() { try { mightThrow(); } catch ( e ) { if ( jQuery.Deferred.exceptionHook ) { jQuery.Deferred.exceptionHook( e, process.stackTrace ); } // Support: Promises/A+ section 2.3.3.3.4.1 // https://promisesaplus.com/#point-61 // Ignore post-resolution exceptions if ( depth + 1 >= maxDepth ) { // Only substitute handlers pass on context // and multiple values (non-spec behavior) if ( handler !== Thrower ) { that = undefined; args = [ e ]; } deferred.rejectWith( that, args ); } } }; // Support: Promises/A+ section 2.3.3.3.1 // https://promisesaplus.com/#point-57 // Re-resolve promises immediately to dodge false rejection from // subsequent errors if ( depth ) { process(); } else { // Call an optional hook to record the stack, in case of exception // since it's otherwise lost when execution goes async if ( jQuery.Deferred.getStackHook ) { process.stackTrace = jQuery.Deferred.getStackHook(); } window.setTimeout( process ); } }; } return jQuery.Deferred( function( newDefer ) { // progress_handlers.add( ... ) tuples[ 0 ][ 3 ].add( resolve( 0, newDefer, jQuery.isFunction( onProgress ) ? onProgress : Identity, newDefer.notifyWith ) ); // fulfilled_handlers.add( ... ) tuples[ 1 ][ 3 ].add( resolve( 0, newDefer, jQuery.isFunction( onFulfilled ) ? onFulfilled : Identity ) ); // rejected_handlers.add( ... ) tuples[ 2 ][ 3 ].add( resolve( 0, newDefer, jQuery.isFunction( onRejected ) ? onRejected : Thrower ) ); } ).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { return obj != null ? jQuery.extend( obj, promise ) : promise; } }, deferred = {}; // Add list-specific methods jQuery.each( tuples, function( i, tuple ) { var list = tuple[ 2 ], stateString = tuple[ 5 ]; // promise.progress = list.add // promise.done = list.add // promise.fail = list.add promise[ tuple[ 1 ] ] = list.add; // Handle state if ( stateString ) { list.add( function() { // state = "resolved" (i.e., fulfilled) // state = "rejected" state = stateString; }, // rejected_callbacks.disable // fulfilled_callbacks.disable tuples[ 3 - i ][ 2 ].disable, // progress_callbacks.lock tuples[ 0 ][ 2 ].lock ); } // progress_handlers.fire // fulfilled_handlers.fire // rejected_handlers.fire list.add( tuple[ 3 ].fire ); // deferred.notify = function() { deferred.notifyWith(...) } // deferred.resolve = function() { deferred.resolveWith(...) } // deferred.reject = function() { deferred.rejectWith(...) } deferred[ tuple[ 0 ] ] = function() { deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); return this; }; // deferred.notifyWith = list.fireWith // deferred.resolveWith = list.fireWith // deferred.rejectWith = list.fireWith deferred[ tuple[ 0 ] + "With" ] = list.fireWith; } ); // Make the deferred a promise promise.promise( deferred ); // Call given func if any if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; }, // Deferred helper when: function( singleValue ) { var // count of uncompleted subordinates remaining = arguments.length, // count of unprocessed arguments i = remaining, // subordinate fulfillment data resolveContexts = Array( i ), resolveValues = slice.call( arguments ), // the master Deferred master = jQuery.Deferred(), // subordinate callback factory updateFunc = function( i ) { return function( value ) { resolveContexts[ i ] = this; resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; if ( !( --remaining ) ) { master.resolveWith( resolveContexts, resolveValues ); } }; }; // Single- and empty arguments are adopted like Promise.resolve if ( remaining <= 1 ) { adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, !remaining ); // Use .then() to unwrap secondary thenables (cf. gh-3000) if ( master.state() === "pending" || jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { return master.then(); } } // Multiple arguments are aggregated like Promise.all array elements while ( i-- ) { adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); } return master.promise(); } } ); // These usually indicate a programmer mistake during development, // warn about them ASAP rather than swallowing them by default. var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; jQuery.Deferred.exceptionHook = function( error, stack ) { // Support: IE 8 - 9 only // Console exists when dev tools are open, which can happen at any time if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); } }; jQuery.readyException = function( error ) { window.setTimeout( function() { throw error; } ); }; // The deferred used on DOM ready var readyList = jQuery.Deferred(); jQuery.fn.ready = function( fn ) { readyList .then( fn ) // Wrap jQuery.readyException in a function so that the lookup // happens at the time of error handling instead of callback // registration. .catch( function( error ) { jQuery.readyException( error ); } ); return this; }; jQuery.extend( { // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1, // Handle when the DOM is ready ready: function( wait ) { // Abort if there are pending holds or we're already ready if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { return; } // Remember that the DOM is ready jQuery.isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be if ( wait !== true && --jQuery.readyWait > 0 ) { return; } // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); } } ); jQuery.ready.then = readyList.then; // The ready event handler and self cleanup method function completed() { document.removeEventListener( "DOMContentLoaded", completed ); window.removeEventListener( "load", completed ); jQuery.ready(); } // Catch cases where $(document).ready() is called // after the browser event has already occurred. // Support: IE <=9 - 10 only // Older IE sometimes signals "interactive" too soon if ( document.readyState === "complete" || ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { // Handle it asynchronously to allow scripts the opportunity to delay ready window.setTimeout( jQuery.ready ); } else { // Use the handy event callback document.addEventListener( "DOMContentLoaded", completed ); // A fallback to window.onload, that will always work window.addEventListener( "load", completed ); } // Multifunctional method to get and set values of a collection // The value/s can optionally be executed if it's a function var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, len = elems.length, bulk = key == null; // Sets many values if ( jQuery.type( key ) === "object" ) { chainable = true; for ( i in key ) { access( elems, fn, i, key[ i ], true, emptyGet, raw ); } // Sets one value } else if ( value !== undefined ) { chainable = true; if ( !jQuery.isFunction( value ) ) { raw = true; } if ( bulk ) { // Bulk operations run against the entire set if ( raw ) { fn.call( elems, value ); fn = null; // ...except when executing function values } else { bulk = fn; fn = function( elem, key, value ) { return bulk.call( jQuery( elem ), value ); }; } } if ( fn ) { for ( ; i < len; i++ ) { fn( elems[ i ], key, raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) ) ); } } } if ( chainable ) { return elems; } // Gets if ( bulk ) { return fn.call( elems ); } return len ? fn( elems[ 0 ], key ) : emptyGet; }; var acceptData = function( owner ) { // Accepts only: // - Node // - Node.ELEMENT_NODE // - Node.DOCUMENT_NODE // - Object // - Any return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); }; function Data() { this.expando = jQuery.expando + Data.uid++; } Data.uid = 1; Data.prototype = { cache: function( owner ) { // Check if the owner object already has a cache var value = owner[ this.expando ]; // If not, create one if ( !value ) { value = {}; // We can accept data for non-element nodes in modern browsers, // but we should not, see #8335. // Always return an empty object. if ( acceptData( owner ) ) { // If it is a node unlikely to be stringify-ed or looped over // use plain assignment if ( owner.nodeType ) { owner[ this.expando ] = value; // Otherwise secure it in a non-enumerable property // configurable must be true to allow the property to be // deleted when data is removed } else { Object.defineProperty( owner, this.expando, { value: value, configurable: true } ); } } } return value; }, set: function( owner, data, value ) { var prop, cache = this.cache( owner ); // Handle: [ owner, key, value ] args // Always use camelCase key (gh-2257) if ( typeof data === "string" ) { cache[ jQuery.camelCase( data ) ] = value; // Handle: [ owner, { properties } ] args } else { // Copy the properties one-by-one to the cache object for ( prop in data ) { cache[ jQuery.camelCase( prop ) ] = data[ prop ]; } } return cache; }, get: function( owner, key ) { return key === undefined ? this.cache( owner ) : // Always use camelCase key (gh-2257) owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; }, access: function( owner, key, value ) { // In cases where either: // // 1. No key was specified // 2. A string key was specified, but no value provided // // Take the "read" path and allow the get method to determine // which value to return, respectively either: // // 1. The entire cache object // 2. The data stored at the key // if ( key === undefined || ( ( key && typeof key === "string" ) && value === undefined ) ) { return this.get( owner, key ); } // When the key is not a string, or both a key and value // are specified, set or extend (existing objects) with either: // // 1. An object of properties // 2. A key and value // this.set( owner, key, value ); // Since the "set" path can have two possible entry points // return the expected data based on which path was taken[*] return value !== undefined ? value : key; }, remove: function( owner, key ) { var i, cache = owner[ this.expando ]; if ( cache === undefined ) { return; } if ( key !== undefined ) { // Support array or space separated string of keys if ( Array.isArray( key ) ) { // If key is an array of keys... // We always set camelCase keys, so remove that. key = key.map( jQuery.camelCase ); } else { key = jQuery.camelCase( key ); // If a key with the spaces exists, use it. // Otherwise, create an array by matching non-whitespace key = key in cache ? [ key ] : ( key.match( rnothtmlwhite ) || [] ); } i = key.length; while ( i-- ) { delete cache[ key[ i ] ]; } } // Remove the expando if there's no more data if ( key === undefined || jQuery.isEmptyObject( cache ) ) { // Support: Chrome <=35 - 45 // Webkit & Blink performance suffers when deleting properties // from DOM nodes, so set to undefined instead // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) if ( owner.nodeType ) { owner[ this.expando ] = undefined; } else { delete owner[ this.expando ]; } } }, hasData: function( owner ) { var cache = owner[ this.expando ]; return cache !== undefined && !jQuery.isEmptyObject( cache ); } }; var dataPriv = new Data(); var dataUser = new Data(); // Implementation Summary // // 1. Enforce API surface and semantic compatibility with 1.9.x branch // 2. Improve the module's maintainability by reducing the storage // paths to a single mechanism. // 3. Use the same single mechanism to support "private" and "user" data. // 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) // 5. Avoid exposing implementation details on user objects (eg. expando properties) // 6. Provide a clear path for implementation upgrade to WeakMap in 2014 var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, rmultiDash = /[A-Z]/g; function getData( data ) { if ( data === "true" ) { return true; } if ( data === "false" ) { return false; } if ( data === "null" ) { return null; } // Only convert to a number if it doesn't change the string if ( data === +data + "" ) { return +data; } if ( rbrace.test( data ) ) { return JSON.parse( data ); } return data; } function dataAttr( elem, key, data ) { var name; // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = getData( data ); } catch ( e ) {} // Make sure we set the data so it isn't changed later dataUser.set( elem, key, data ); } else { data = undefined; } } return data; } jQuery.extend( { hasData: function( elem ) { return dataUser.hasData( elem ) || dataPriv.hasData( elem ); }, data: function( elem, name, data ) { return dataUser.access( elem, name, data ); }, removeData: function( elem, name ) { dataUser.remove( elem, name ); }, // TODO: Now that all calls to _data and _removeData have been replaced // with direct calls to dataPriv methods, these can be deprecated. _data: function( elem, name, data ) { return dataPriv.access( elem, name, data ); }, _removeData: function( elem, name ) { dataPriv.remove( elem, name ); } } ); jQuery.fn.extend( { data: function( key, value ) { var i, name, data, elem = this[ 0 ], attrs = elem && elem.attributes; // Gets all values if ( key === undefined ) { if ( this.length ) { data = dataUser.get( elem ); if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { i = attrs.length; while ( i-- ) { // Support: IE 11 only // The attrs elements can be null (#14894) if ( attrs[ i ] ) { name = attrs[ i ].name; if ( name.indexOf( "data-" ) === 0 ) { name = jQuery.camelCase( name.slice( 5 ) ); dataAttr( elem, name, data[ name ] ); } } } dataPriv.set( elem, "hasDataAttrs", true ); } } return data; } // Sets multiple values if ( typeof key === "object" ) { return this.each( function() { dataUser.set( this, key ); } ); } return access( this, function( value ) { var data; // The calling jQuery object (element matches) is not empty // (and therefore has an element appears at this[ 0 ]) and the // `value` parameter was not undefined. An empty jQuery object // will result in `undefined` for elem = this[ 0 ] which will // throw an exception if an attempt to read a data cache is made. if ( elem && value === undefined ) { // Attempt to get data from the cache // The key will always be camelCased in Data data = dataUser.get( elem, key ); if ( data !== undefined ) { return data; } // Attempt to "discover" the data in // HTML5 custom data-* attrs data = dataAttr( elem, key ); if ( data !== undefined ) { return data; } // We tried really hard, but the data doesn't exist. return; } // Set the data... this.each( function() { // We always store the camelCased key dataUser.set( this, key, value ); } ); }, null, value, arguments.length > 1, null, true ); }, removeData: function( key ) { return this.each( function() { dataUser.remove( this, key ); } ); } } ); jQuery.extend( { queue: function( elem, type, data ) { var queue; if ( elem ) { type = ( type || "fx" ) + "queue"; queue = dataPriv.get( elem, type ); // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { if ( !queue || Array.isArray( data ) ) { queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); } else { queue.push( data ); } } return queue || []; } }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), startLength = queue.length, fn = queue.shift(), hooks = jQuery._queueHooks( elem, type ), next = function() { jQuery.dequeue( elem, type ); }; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { fn = queue.shift(); startLength--; } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { queue.unshift( "inprogress" ); } // Clear up the last queue stop function delete hooks.stop; fn.call( elem, next, hooks ); } if ( !startLength && hooks ) { hooks.empty.fire(); } }, // Not public - generate a queueHooks object, or return the current one _queueHooks: function( elem, type ) { var key = type + "queueHooks"; return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { empty: jQuery.Callbacks( "once memory" ).add( function() { dataPriv.remove( elem, [ type + "queue", key ] ); } ) } ); } } ); jQuery.fn.extend( { queue: function( type, data ) { var setter = 2; if ( typeof type !== "string" ) { data = type; type = "fx"; setter--; } if ( arguments.length < setter ) { return jQuery.queue( this[ 0 ], type ); } return data === undefined ? this : this.each( function() { var queue = jQuery.queue( this, type, data ); // Ensure a hooks for this queue jQuery._queueHooks( this, type ); if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { jQuery.dequeue( this, type ); } } ); }, dequeue: function( type ) { return this.each( function() { jQuery.dequeue( this, type ); } ); }, clearQueue: function( type ) { return this.queue( type || "fx", [] ); }, // Get a promise resolved when queues of a certain type // are emptied (fx is the type by default) promise: function( type, obj ) { var tmp, count = 1, defer = jQuery.Deferred(), elements = this, i = this.length, resolve = function() { if ( !( --count ) ) { defer.resolveWith( elements, [ elements ] ); } }; if ( typeof type !== "string" ) { obj = type; type = undefined; } type = type || "fx"; while ( i-- ) { tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); if ( tmp && tmp.empty ) { count++; tmp.empty.add( resolve ); } } resolve(); return defer.promise( obj ); } } ); var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; var isHiddenWithinTree = function( elem, el ) { // isHiddenWithinTree might be called from jQuery#filter function; // in that case, element will be second argument elem = el || elem; // Inline style trumps all return elem.style.display === "none" || elem.style.display === "" && // Otherwise, check computed style // Support: Firefox <=43 - 45 // Disconnected elements can have computed display: none, so first confirm that elem is // in the document. jQuery.contains( elem.ownerDocument, elem ) && jQuery.css( elem, "display" ) === "none"; }; var swap = function( elem, options, callback, args ) { var ret, name, old = {}; // Remember the old values, and insert the new ones for ( name in options ) { old[ name ] = elem.style[ name ]; elem.style[ name ] = options[ name ]; } ret = callback.apply( elem, args || [] ); // Revert the old values for ( name in options ) { elem.style[ name ] = old[ name ]; } return ret; }; function adjustCSS( elem, prop, valueParts, tween ) { var adjusted, scale = 1, maxIterations = 20, currentValue = tween ? function() { return tween.cur(); } : function() { return jQuery.css( elem, prop, "" ); }, initial = currentValue(), unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), // Starting value computation is required for potential unit mismatches initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && rcssNum.exec( jQuery.css( elem, prop ) ); if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { // Trust units reported by jQuery.css unit = unit || initialInUnit[ 3 ]; // Make sure we update the tween properties later on valueParts = valueParts || []; // Iteratively approximate from a nonzero starting point initialInUnit = +initial || 1; do { // If previous iteration zeroed out, double until we get *something*. // Use string for doubling so we don't accidentally see scale as unchanged below scale = scale || ".5"; // Adjust and apply initialInUnit = initialInUnit / scale; jQuery.style( elem, prop, initialInUnit + unit ); // Update scale, tolerating zero or NaN from tween.cur() // Break the loop if scale is unchanged or perfect, or if we've just had enough. } while ( scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations ); } if ( valueParts ) { initialInUnit = +initialInUnit || +initial || 0; // Apply relative offset (+=/-=) if specified adjusted = valueParts[ 1 ] ? initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : +valueParts[ 2 ]; if ( tween ) { tween.unit = unit; tween.start = initialInUnit; tween.end = adjusted; } } return adjusted; } var defaultDisplayMap = {}; function getDefaultDisplay( elem ) { var temp, doc = elem.ownerDocument, nodeName = elem.nodeName, display = defaultDisplayMap[ nodeName ]; if ( display ) { return display; } temp = doc.body.appendChild( doc.createElement( nodeName ) ); display = jQuery.css( temp, "display" ); temp.parentNode.removeChild( temp ); if ( display === "none" ) { display = "block"; } defaultDisplayMap[ nodeName ] = display; return display; } function showHide( elements, show ) { var display, elem, values = [], index = 0, length = elements.length; // Determine new display value for elements that need to change for ( ; index < length; index++ ) { elem = elements[ index ]; if ( !elem.style ) { continue; } display = elem.style.display; if ( show ) { // Since we force visibility upon cascade-hidden elements, an immediate (and slow) // check is required in this first loop unless we have a nonempty display value (either // inline or about-to-be-restored) if ( display === "none" ) { values[ index ] = dataPriv.get( elem, "display" ) || null; if ( !values[ index ] ) { elem.style.display = ""; } } if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { values[ index ] = getDefaultDisplay( elem ); } } else { if ( display !== "none" ) { values[ index ] = "none"; // Remember what we're overwriting dataPriv.set( elem, "display", display ); } } } // Set the display of the elements in a second loop to avoid constant reflow for ( index = 0; index < length; index++ ) { if ( values[ index ] != null ) { elements[ index ].style.display = values[ index ]; } } return elements; } jQuery.fn.extend( { show: function() { return showHide( this, true ); }, hide: function() { return showHide( this ); }, toggle: function( state ) { if ( typeof state === "boolean" ) { return state ? this.show() : this.hide(); } return this.each( function() { if ( isHiddenWithinTree( this ) ) { jQuery( this ).show(); } else { jQuery( this ).hide(); } } ); } } ); var rcheckableType = ( /^(?:checkbox|radio)$/i ); var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); var rscriptType = ( /^$|\/(?:java|ecma)script/i ); // We have to close these tags to support XHTML (#13200) var wrapMap = { // Support: IE <=9 only option: [ 1, "" ], // XHTML parsers do not magically insert elements in the // same way that tag soup parsers do. So we cannot shorten // this by omitting or other required elements. thead: [ 1, "", "
" ], col: [ 2, "", "
" ], tr: [ 2, "", "
" ], td: [ 3, "", "
" ], _default: [ 0, "", "" ] }; // Support: IE <=9 only wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; function getAll( context, tag ) { // Support: IE <=9 - 11 only // Use typeof to avoid zero-argument method invocation on host objects (#15151) var ret; if ( typeof context.getElementsByTagName !== "undefined" ) { ret = context.getElementsByTagName( tag || "*" ); } else if ( typeof context.querySelectorAll !== "undefined" ) { ret = context.querySelectorAll( tag || "*" ); } else { ret = []; } if ( tag === undefined || tag && nodeName( context, tag ) ) { return jQuery.merge( [ context ], ret ); } return ret; } // Mark scripts as having already been evaluated function setGlobalEval( elems, refElements ) { var i = 0, l = elems.length; for ( ; i < l; i++ ) { dataPriv.set( elems[ i ], "globalEval", !refElements || dataPriv.get( refElements[ i ], "globalEval" ) ); } } var rhtml = /<|&#?\w+;/; function buildFragment( elems, context, scripts, selection, ignored ) { var elem, tmp, tag, wrap, contains, j, fragment = context.createDocumentFragment(), nodes = [], i = 0, l = elems.length; for ( ; i < l; i++ ) { elem = elems[ i ]; if ( elem || elem === 0 ) { // Add nodes directly if ( jQuery.type( elem ) === "object" ) { // Support: Android <=4.0 only, PhantomJS 1 only // push.apply(_, arraylike) throws on ancient WebKit jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); // Convert non-html into a text node } else if ( !rhtml.test( elem ) ) { nodes.push( context.createTextNode( elem ) ); // Convert html into DOM nodes } else { tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); // Deserialize a standard representation tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); wrap = wrapMap[ tag ] || wrapMap._default; tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; // Descend through wrappers to the right content j = wrap[ 0 ]; while ( j-- ) { tmp = tmp.lastChild; } // Support: Android <=4.0 only, PhantomJS 1 only // push.apply(_, arraylike) throws on ancient WebKit jQuery.merge( nodes, tmp.childNodes ); // Remember the top-level container tmp = fragment.firstChild; // Ensure the created nodes are orphaned (#12392) tmp.textContent = ""; } } } // Remove wrapper from fragment fragment.textContent = ""; i = 0; while ( ( elem = nodes[ i++ ] ) ) { // Skip elements already in the context collection (trac-4087) if ( selection && jQuery.inArray( elem, selection ) > -1 ) { if ( ignored ) { ignored.push( elem ); } continue; } contains = jQuery.contains( elem.ownerDocument, elem ); // Append to fragment tmp = getAll( fragment.appendChild( elem ), "script" ); // Preserve script evaluation history if ( contains ) { setGlobalEval( tmp ); } // Capture executables if ( scripts ) { j = 0; while ( ( elem = tmp[ j++ ] ) ) { if ( rscriptType.test( elem.type || "" ) ) { scripts.push( elem ); } } } } return fragment; } ( function() { var fragment = document.createDocumentFragment(), div = fragment.appendChild( document.createElement( "div" ) ), input = document.createElement( "input" ); // Support: Android 4.0 - 4.3 only // Check state lost if the name is set (#11217) // Support: Windows Web Apps (WWA) // `name` and `type` must use .setAttribute for WWA (#14901) input.setAttribute( "type", "radio" ); input.setAttribute( "checked", "checked" ); input.setAttribute( "name", "t" ); div.appendChild( input ); // Support: Android <=4.1 only // Older WebKit doesn't clone checked state correctly in fragments support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; // Support: IE <=11 only // Make sure textarea (and checkbox) defaultValue is properly cloned div.innerHTML = ""; support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; } )(); var documentElement = document.documentElement; var rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, rtypenamespace = /^([^.]*)(?:\.(.+)|)/; function returnTrue() { return true; } function returnFalse() { return false; } // Support: IE <=9 only // See #13393 for more info function safeActiveElement() { try { return document.activeElement; } catch ( err ) { } } function on( elem, types, selector, data, fn, one ) { var origFn, type; // Types can be a map of types/handlers if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // ( types-Object, data ) data = data || selector; selector = undefined; } for ( type in types ) { on( elem, type, selector, data, types[ type ], one ); } return elem; } if ( data == null && fn == null ) { // ( types, fn ) fn = selector; data = selector = undefined; } else if ( fn == null ) { if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn ) fn = data; data = selector; selector = undefined; } } if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { return elem; } if ( one === 1 ) { origFn = fn; fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } return elem.each( function() { jQuery.event.add( this, types, fn, data, selector ); } ); } /* * Helper functions for managing events -- not part of the public interface. * Props to Dean Edwards' addEvent library for many of the ideas. */ jQuery.event = { global: {}, add: function( elem, types, handler, data, selector ) { var handleObjIn, eventHandle, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = dataPriv.get( elem ); // Don't attach events to noData or text/comment nodes (but allow plain objects) if ( !elemData ) { return; } // Caller can pass in an object of custom data in lieu of the handler if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; selector = handleObjIn.selector; } // Ensure that invalid selectors throw exceptions at attach time // Evaluate against documentElement in case elem is a non-element node (e.g., document) if ( selector ) { jQuery.find.matchesSelector( documentElement, selector ); } // Make sure that the handler has a unique ID, used to find/remove it later if ( !handler.guid ) { handler.guid = jQuery.guid++; } // Init the element's event structure and main handler, if this is the first if ( !( events = elemData.events ) ) { events = elemData.events = {}; } if ( !( eventHandle = elemData.handle ) ) { eventHandle = elemData.handle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? jQuery.event.dispatch.apply( elem, arguments ) : undefined; }; } // Handle multiple events separated by a space types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[ t ] ) || []; type = origType = tmp[ 1 ]; namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); // There *must* be a type, no attaching namespace-only handlers if ( !type ) { continue; } // If event changes its type, use the special event handlers for the changed type special = jQuery.event.special[ type ] || {}; // If selector defined, determine special event api type, otherwise given type type = ( selector ? special.delegateType : special.bindType ) || type; // Update special based on newly reset type special = jQuery.event.special[ type ] || {}; // handleObj is passed to all event handlers handleObj = jQuery.extend( { type: type, origType: origType, data: data, handler: handler, guid: handler.guid, selector: selector, needsContext: selector && jQuery.expr.match.needsContext.test( selector ), namespace: namespaces.join( "." ) }, handleObjIn ); // Init the event handler queue if we're the first if ( !( handlers = events[ type ] ) ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle ); } } } if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // Add to the element's handler list, delegates in front if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } // Keep track of which events have ever been used, for event optimization jQuery.event.global[ type ] = true; } }, // Detach an event or set of events from an element remove: function( elem, types, handler, selector, mappedTypes ) { var j, origCount, tmp, events, t, handleObj, special, handlers, type, namespaces, origType, elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); if ( !elemData || !( events = elemData.events ) ) { return; } // Once for each type.namespace in types; type may be omitted types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[ t ] ) || []; type = origType = tmp[ 1 ]; namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); // Unbind all events (on this namespace, if provided) for the element if ( !type ) { for ( type in events ) { jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); } continue; } special = jQuery.event.special[ type ] || {}; type = ( selector ? special.delegateType : special.bindType ) || type; handlers = events[ type ] || []; tmp = tmp[ 2 ] && new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); // Remove matching events origCount = j = handlers.length; while ( j-- ) { handleObj = handlers[ j ]; if ( ( mappedTypes || origType === handleObj.origType ) && ( !handler || handler.guid === handleObj.guid ) && ( !tmp || tmp.test( handleObj.namespace ) ) && ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { handlers.splice( j, 1 ); if ( handleObj.selector ) { handlers.delegateCount--; } if ( special.remove ) { special.remove.call( elem, handleObj ); } } } // Remove generic event handler if we removed something and no more handlers exist // (avoids potential for endless recursion during removal of special event handlers) if ( origCount && !handlers.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } delete events[ type ]; } } // Remove data and the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { dataPriv.remove( elem, "handle events" ); } }, dispatch: function( nativeEvent ) { // Make a writable jQuery.Event from the native event object var event = jQuery.event.fix( nativeEvent ); var i, j, ret, matched, handleObj, handlerQueue, args = new Array( arguments.length ), handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event args[ 0 ] = event; for ( i = 1; i < arguments.length; i++ ) { args[ i ] = arguments[ i ]; } event.delegateTarget = this; // Call the preDispatch hook for the mapped type, and let it bail if desired if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { return; } // Determine handlers handlerQueue = jQuery.event.handlers.call( this, event, handlers ); // Run delegates first; they may want to stop propagation beneath us i = 0; while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { event.currentTarget = matched.elem; j = 0; while ( ( handleObj = matched.handlers[ j++ ] ) && !event.isImmediatePropagationStopped() ) { // Triggered event must either 1) have no namespace, or 2) have namespace(s) // a subset or equal to those in the bound event (both can have no namespace). if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { event.handleObj = handleObj; event.data = handleObj.data; ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || handleObj.handler ).apply( matched.elem, args ); if ( ret !== undefined ) { if ( ( event.result = ret ) === false ) { event.preventDefault(); event.stopPropagation(); } } } } } // Call the postDispatch hook for the mapped type if ( special.postDispatch ) { special.postDispatch.call( this, event ); } return event.result; }, handlers: function( event, handlers ) { var i, handleObj, sel, matchedHandlers, matchedSelectors, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target; // Find delegate handlers if ( delegateCount && // Support: IE <=9 // Black-hole SVG instance trees (trac-13180) cur.nodeType && // Support: Firefox <=42 // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click // Support: IE 11 only // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) !( event.type === "click" && event.button >= 1 ) ) { for ( ; cur !== this; cur = cur.parentNode || this ) { // Don't check non-elements (#13208) // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { matchedHandlers = []; matchedSelectors = {}; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; // Don't conflict with Object.prototype properties (#13203) sel = handleObj.selector + " "; if ( matchedSelectors[ sel ] === undefined ) { matchedSelectors[ sel ] = handleObj.needsContext ? jQuery( sel, this ).index( cur ) > -1 : jQuery.find( sel, this, null, [ cur ] ).length; } if ( matchedSelectors[ sel ] ) { matchedHandlers.push( handleObj ); } } if ( matchedHandlers.length ) { handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); } } } } // Add the remaining (directly-bound) handlers cur = this; if ( delegateCount < handlers.length ) { handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); } return handlerQueue; }, addProp: function( name, hook ) { Object.defineProperty( jQuery.Event.prototype, name, { enumerable: true, configurable: true, get: jQuery.isFunction( hook ) ? function() { if ( this.originalEvent ) { return hook( this.originalEvent ); } } : function() { if ( this.originalEvent ) { return this.originalEvent[ name ]; } }, set: function( value ) { Object.defineProperty( this, name, { enumerable: true, configurable: true, writable: true, value: value } ); } } ); }, fix: function( originalEvent ) { return originalEvent[ jQuery.expando ] ? originalEvent : new jQuery.Event( originalEvent ); }, special: { load: { // Prevent triggered image.load events from bubbling to window.load noBubble: true }, focus: { // Fire native event if possible so blur/focus sequence is correct trigger: function() { if ( this !== safeActiveElement() && this.focus ) { this.focus(); return false; } }, delegateType: "focusin" }, blur: { trigger: function() { if ( this === safeActiveElement() && this.blur ) { this.blur(); return false; } }, delegateType: "focusout" }, click: { // For checkbox, fire native event so checked state will be right trigger: function() { if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { this.click(); return false; } }, // For cross-browser consistency, don't fire native .click() on links _default: function( event ) { return nodeName( event.target, "a" ); } }, beforeunload: { postDispatch: function( event ) { // Support: Firefox 20+ // Firefox doesn't alert if the returnValue field is not set. if ( event.result !== undefined && event.originalEvent ) { event.originalEvent.returnValue = event.result; } } } } }; jQuery.removeEvent = function( elem, type, handle ) { // This "if" is needed for plain objects if ( elem.removeEventListener ) { elem.removeEventListener( type, handle ); } }; jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !( this instanceof jQuery.Event ) ) { return new jQuery.Event( src, props ); } // Event object if ( src && src.type ) { this.originalEvent = src; this.type = src.type; // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === undefined && // Support: Android <=2.3 only src.returnValue === false ? returnTrue : returnFalse; // Create target properties // Support: Safari <=6 - 7 only // Target should not be a text node (#504, #13143) this.target = ( src.target && src.target.nodeType === 3 ) ? src.target.parentNode : src.target; this.currentTarget = src.currentTarget; this.relatedTarget = src.relatedTarget; // Event type } else { this.type = src; } // Put explicitly provided properties onto the event object if ( props ) { jQuery.extend( this, props ); } // Create a timestamp if incoming event doesn't have one this.timeStamp = src && src.timeStamp || jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; }; // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding // https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { constructor: jQuery.Event, isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse, isSimulated: false, preventDefault: function() { var e = this.originalEvent; this.isDefaultPrevented = returnTrue; if ( e && !this.isSimulated ) { e.preventDefault(); } }, stopPropagation: function() { var e = this.originalEvent; this.isPropagationStopped = returnTrue; if ( e && !this.isSimulated ) { e.stopPropagation(); } }, stopImmediatePropagation: function() { var e = this.originalEvent; this.isImmediatePropagationStopped = returnTrue; if ( e && !this.isSimulated ) { e.stopImmediatePropagation(); } this.stopPropagation(); } }; // Includes all common event props including KeyEvent and MouseEvent specific props jQuery.each( { altKey: true, bubbles: true, cancelable: true, changedTouches: true, ctrlKey: true, detail: true, eventPhase: true, metaKey: true, pageX: true, pageY: true, shiftKey: true, view: true, "char": true, charCode: true, key: true, keyCode: true, button: true, buttons: true, clientX: true, clientY: true, offsetX: true, offsetY: true, pointerId: true, pointerType: true, screenX: true, screenY: true, targetTouches: true, toElement: true, touches: true, which: function( event ) { var button = event.button; // Add which for key events if ( event.which == null && rkeyEvent.test( event.type ) ) { return event.charCode != null ? event.charCode : event.keyCode; } // Add which for click: 1 === left; 2 === middle; 3 === right if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { if ( button & 1 ) { return 1; } if ( button & 2 ) { return 3; } if ( button & 4 ) { return 2; } return 0; } return event.which; } }, jQuery.event.addProp ); // Create mouseenter/leave events using mouseover/out and event-time checks // so that event delegation works in jQuery. // Do the same for pointerenter/pointerleave and pointerover/pointerout // // Support: Safari 7 only // Safari sends mouseenter too often; see: // https://bugs.chromium.org/p/chromium/issues/detail?id=470258 // for the description of the bug (it existed in older Chrome versions as well). jQuery.each( { mouseenter: "mouseover", mouseleave: "mouseout", pointerenter: "pointerover", pointerleave: "pointerout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { delegateType: fix, bindType: fix, handle: function( event ) { var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj; // For mouseenter/leave call the handler if related is outside the target. // NB: No relatedTarget if the mouse left/entered the browser window if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { event.type = handleObj.origType; ret = handleObj.handler.apply( this, arguments ); event.type = fix; } return ret; } }; } ); jQuery.fn.extend( { on: function( types, selector, data, fn ) { return on( this, types, selector, data, fn ); }, one: function( types, selector, data, fn ) { return on( this, types, selector, data, fn, 1 ); }, off: function( types, selector, fn ) { var handleObj, type; if ( types && types.preventDefault && types.handleObj ) { // ( event ) dispatched jQuery.Event handleObj = types.handleObj; jQuery( types.delegateTarget ).off( handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler ); return this; } if ( typeof types === "object" ) { // ( types-object [, selector] ) for ( type in types ) { this.off( type, selector, types[ type ] ); } return this; } if ( selector === false || typeof selector === "function" ) { // ( types [, fn] ) fn = selector; selector = undefined; } if ( fn === false ) { fn = returnFalse; } return this.each( function() { jQuery.event.remove( this, types, fn, selector ); } ); } } ); var /* eslint-disable max-len */ // See https://github.com/eslint/eslint/issues/3229 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, /* eslint-enable */ // Support: IE <=10 - 11, Edge 12 - 13 // In IE/Edge using regex groups here causes severe slowdowns. // See https://connect.microsoft.com/IE/feedback/details/1736512/ rnoInnerhtml = /\s*$/g; // Prefer a tbody over its parent table for containing new rows function manipulationTarget( elem, content ) { if ( nodeName( elem, "table" ) && nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { return jQuery( ">tbody", elem )[ 0 ] || elem; } return elem; } // Replace/restore the type attribute of script elements for safe DOM manipulation function disableScript( elem ) { elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; return elem; } function restoreScript( elem ) { var match = rscriptTypeMasked.exec( elem.type ); if ( match ) { elem.type = match[ 1 ]; } else { elem.removeAttribute( "type" ); } return elem; } function cloneCopyEvent( src, dest ) { var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; if ( dest.nodeType !== 1 ) { return; } // 1. Copy private data: events, handlers, etc. if ( dataPriv.hasData( src ) ) { pdataOld = dataPriv.access( src ); pdataCur = dataPriv.set( dest, pdataOld ); events = pdataOld.events; if ( events ) { delete pdataCur.handle; pdataCur.events = {}; for ( type in events ) { for ( i = 0, l = events[ type ].length; i < l; i++ ) { jQuery.event.add( dest, type, events[ type ][ i ] ); } } } } // 2. Copy user data if ( dataUser.hasData( src ) ) { udataOld = dataUser.access( src ); udataCur = jQuery.extend( {}, udataOld ); dataUser.set( dest, udataCur ); } } // Fix IE bugs, see support tests function fixInput( src, dest ) { var nodeName = dest.nodeName.toLowerCase(); // Fails to persist the checked state of a cloned checkbox or radio button. if ( nodeName === "input" && rcheckableType.test( src.type ) ) { dest.checked = src.checked; // Fails to return the selected option to the default selected state when cloning options } else if ( nodeName === "input" || nodeName === "textarea" ) { dest.defaultValue = src.defaultValue; } } function domManip( collection, args, callback, ignored ) { // Flatten any nested arrays args = concat.apply( [], args ); var fragment, first, scripts, hasScripts, node, doc, i = 0, l = collection.length, iNoClone = l - 1, value = args[ 0 ], isFunction = jQuery.isFunction( value ); // We can't cloneNode fragments that contain checked, in WebKit if ( isFunction || ( l > 1 && typeof value === "string" && !support.checkClone && rchecked.test( value ) ) ) { return collection.each( function( index ) { var self = collection.eq( index ); if ( isFunction ) { args[ 0 ] = value.call( this, index, self.html() ); } domManip( self, args, callback, ignored ); } ); } if ( l ) { fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); first = fragment.firstChild; if ( fragment.childNodes.length === 1 ) { fragment = first; } // Require either new content or an interest in ignored elements to invoke the callback if ( first || ignored ) { scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); hasScripts = scripts.length; // Use the original fragment for the last item // instead of the first because it can end up // being emptied incorrectly in certain situations (#8070). for ( ; i < l; i++ ) { node = fragment; if ( i !== iNoClone ) { node = jQuery.clone( node, true, true ); // Keep references to cloned scripts for later restoration if ( hasScripts ) { // Support: Android <=4.0 only, PhantomJS 1 only // push.apply(_, arraylike) throws on ancient WebKit jQuery.merge( scripts, getAll( node, "script" ) ); } } callback.call( collection[ i ], node, i ); } if ( hasScripts ) { doc = scripts[ scripts.length - 1 ].ownerDocument; // Reenable scripts jQuery.map( scripts, restoreScript ); // Evaluate executable scripts on first document insertion for ( i = 0; i < hasScripts; i++ ) { node = scripts[ i ]; if ( rscriptType.test( node.type || "" ) && !dataPriv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) { if ( node.src ) { // Optional AJAX dependency, but won't run scripts if not present if ( jQuery._evalUrl ) { jQuery._evalUrl( node.src ); } } else { DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); } } } } } } return collection; } function remove( elem, selector, keepData ) { var node, nodes = selector ? jQuery.filter( selector, elem ) : elem, i = 0; for ( ; ( node = nodes[ i ] ) != null; i++ ) { if ( !keepData && node.nodeType === 1 ) { jQuery.cleanData( getAll( node ) ); } if ( node.parentNode ) { if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { setGlobalEval( getAll( node, "script" ) ); } node.parentNode.removeChild( node ); } } return elem; } jQuery.extend( { htmlPrefilter: function( html ) { return html.replace( rxhtmlTag, "<$1>" ); }, clone: function( elem, dataAndEvents, deepDataAndEvents ) { var i, l, srcElements, destElements, clone = elem.cloneNode( true ), inPage = jQuery.contains( elem.ownerDocument, elem ); // Fix IE cloning issues if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 destElements = getAll( clone ); srcElements = getAll( elem ); for ( i = 0, l = srcElements.length; i < l; i++ ) { fixInput( srcElements[ i ], destElements[ i ] ); } } // Copy the events from the original to the clone if ( dataAndEvents ) { if ( deepDataAndEvents ) { srcElements = srcElements || getAll( elem ); destElements = destElements || getAll( clone ); for ( i = 0, l = srcElements.length; i < l; i++ ) { cloneCopyEvent( srcElements[ i ], destElements[ i ] ); } } else { cloneCopyEvent( elem, clone ); } } // Preserve script evaluation history destElements = getAll( clone, "script" ); if ( destElements.length > 0 ) { setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); } // Return the cloned set return clone; }, cleanData: function( elems ) { var data, elem, type, special = jQuery.event.special, i = 0; for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { if ( acceptData( elem ) ) { if ( ( data = elem[ dataPriv.expando ] ) ) { if ( data.events ) { for ( type in data.events ) { if ( special[ type ] ) { jQuery.event.remove( elem, type ); // This is a shortcut to avoid jQuery.event.remove's overhead } else { jQuery.removeEvent( elem, type, data.handle ); } } } // Support: Chrome <=35 - 45+ // Assign undefined instead of using delete, see Data#remove elem[ dataPriv.expando ] = undefined; } if ( elem[ dataUser.expando ] ) { // Support: Chrome <=35 - 45+ // Assign undefined instead of using delete, see Data#remove elem[ dataUser.expando ] = undefined; } } } } } ); jQuery.fn.extend( { detach: function( selector ) { return remove( this, selector, true ); }, remove: function( selector ) { return remove( this, selector ); }, text: function( value ) { return access( this, function( value ) { return value === undefined ? jQuery.text( this ) : this.empty().each( function() { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { this.textContent = value; } } ); }, null, value, arguments.length ); }, append: function() { return domManip( this, arguments, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { var target = manipulationTarget( this, elem ); target.appendChild( elem ); } } ); }, prepend: function() { return domManip( this, arguments, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { var target = manipulationTarget( this, elem ); target.insertBefore( elem, target.firstChild ); } } ); }, before: function() { return domManip( this, arguments, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this ); } } ); }, after: function() { return domManip( this, arguments, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this.nextSibling ); } } ); }, empty: function() { var elem, i = 0; for ( ; ( elem = this[ i ] ) != null; i++ ) { if ( elem.nodeType === 1 ) { // Prevent memory leaks jQuery.cleanData( getAll( elem, false ) ); // Remove any remaining nodes elem.textContent = ""; } } return this; }, clone: function( dataAndEvents, deepDataAndEvents ) { dataAndEvents = dataAndEvents == null ? false : dataAndEvents; deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; return this.map( function() { return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); } ); }, html: function( value ) { return access( this, function( value ) { var elem = this[ 0 ] || {}, i = 0, l = this.length; if ( value === undefined && elem.nodeType === 1 ) { return elem.innerHTML; } // See if we can take a shortcut and just use innerHTML if ( typeof value === "string" && !rnoInnerhtml.test( value ) && !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { value = jQuery.htmlPrefilter( value ); try { for ( ; i < l; i++ ) { elem = this[ i ] || {}; // Remove element nodes and prevent memory leaks if ( elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem, false ) ); elem.innerHTML = value; } } elem = 0; // If using innerHTML throws an exception, use the fallback method } catch ( e ) {} } if ( elem ) { this.empty().append( value ); } }, null, value, arguments.length ); }, replaceWith: function() { var ignored = []; // Make the changes, replacing each non-ignored context element with the new content return domManip( this, arguments, function( elem ) { var parent = this.parentNode; if ( jQuery.inArray( this, ignored ) < 0 ) { jQuery.cleanData( getAll( this ) ); if ( parent ) { parent.replaceChild( elem, this ); } } // Force callback invocation }, ignored ); } } ); jQuery.each( { appendTo: "append", prependTo: "prepend", insertBefore: "before", insertAfter: "after", replaceAll: "replaceWith" }, function( name, original ) { jQuery.fn[ name ] = function( selector ) { var elems, ret = [], insert = jQuery( selector ), last = insert.length - 1, i = 0; for ( ; i <= last; i++ ) { elems = i === last ? this : this.clone( true ); jQuery( insert[ i ] )[ original ]( elems ); // Support: Android <=4.0 only, PhantomJS 1 only // .get() because push.apply(_, arraylike) throws on ancient WebKit push.apply( ret, elems.get() ); } return this.pushStack( ret ); }; } ); var rmargin = ( /^margin/ ); var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); var getStyles = function( elem ) { // Support: IE <=11 only, Firefox <=30 (#15098, #14150) // IE throws on elements created in popups // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" var view = elem.ownerDocument.defaultView; if ( !view || !view.opener ) { view = window; } return view.getComputedStyle( elem ); }; ( function() { // Executing both pixelPosition & boxSizingReliable tests require only one layout // so they're executed at the same time to save the second computation. function computeStyleTests() { // This is a singleton, we need to execute it only once if ( !div ) { return; } div.style.cssText = "box-sizing:border-box;" + "position:relative;display:block;" + "margin:auto;border:1px;padding:1px;" + "top:1%;width:50%"; div.innerHTML = ""; documentElement.appendChild( container ); var divStyle = window.getComputedStyle( div ); pixelPositionVal = divStyle.top !== "1%"; // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 reliableMarginLeftVal = divStyle.marginLeft === "2px"; boxSizingReliableVal = divStyle.width === "4px"; // Support: Android 4.0 - 4.3 only // Some styles come back with percentage values, even though they shouldn't div.style.marginRight = "50%"; pixelMarginRightVal = divStyle.marginRight === "4px"; documentElement.removeChild( container ); // Nullify the div so it wouldn't be stored in the memory and // it will also be a sign that checks already performed div = null; } var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, container = document.createElement( "div" ), div = document.createElement( "div" ); // Finish early in limited (non-browser) environments if ( !div.style ) { return; } // Support: IE <=9 - 11 only // Style of cloned element affects source element cloned (#8908) div.style.backgroundClip = "content-box"; div.cloneNode( true ).style.backgroundClip = ""; support.clearCloneStyle = div.style.backgroundClip === "content-box"; container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + "padding:0;margin-top:1px;position:absolute"; container.appendChild( div ); jQuery.extend( support, { pixelPosition: function() { computeStyleTests(); return pixelPositionVal; }, boxSizingReliable: function() { computeStyleTests(); return boxSizingReliableVal; }, pixelMarginRight: function() { computeStyleTests(); return pixelMarginRightVal; }, reliableMarginLeft: function() { computeStyleTests(); return reliableMarginLeftVal; } } ); } )(); function curCSS( elem, name, computed ) { var width, minWidth, maxWidth, ret, // Support: Firefox 51+ // Retrieving style before computed somehow // fixes an issue with getting wrong values // on detached elements style = elem.style; computed = computed || getStyles( elem ); // getPropertyValue is needed for: // .css('filter') (IE 9 only, #12537) // .css('--customProperty) (#3144) if ( computed ) { ret = computed.getPropertyValue( name ) || computed[ name ]; if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { ret = jQuery.style( elem, name ); } // A tribute to the "awesome hack by Dean Edwards" // Android Browser returns percentage for some values, // but width seems to be reliably pixels. // This is against the CSSOM draft spec: // https://drafts.csswg.org/cssom/#resolved-values if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { // Remember the original values width = style.width; minWidth = style.minWidth; maxWidth = style.maxWidth; // Put in the new values to get a computed value out style.minWidth = style.maxWidth = style.width = ret; ret = computed.width; // Revert the changed values style.width = width; style.minWidth = minWidth; style.maxWidth = maxWidth; } } return ret !== undefined ? // Support: IE <=9 - 11 only // IE returns zIndex value as an integer. ret + "" : ret; } function addGetHookIf( conditionFn, hookFn ) { // Define the hook, we'll check on the first run if it's really needed. return { get: function() { if ( conditionFn() ) { // Hook not needed (or it's not possible to use it due // to missing dependency), remove it. delete this.get; return; } // Hook needed; redefine it so that the support test is not executed again. return ( this.get = hookFn ).apply( this, arguments ); } }; } var // Swappable if display is none or starts with table // except "table", "table-cell", or "table-caption" // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display rdisplayswap = /^(none|table(?!-c[ea]).+)/, rcustomProp = /^--/, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = { letterSpacing: "0", fontWeight: "400" }, cssPrefixes = [ "Webkit", "Moz", "ms" ], emptyStyle = document.createElement( "div" ).style; // Return a css property mapped to a potentially vendor prefixed property function vendorPropName( name ) { // Shortcut for names that are not vendor prefixed if ( name in emptyStyle ) { return name; } // Check for vendor prefixed names var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), i = cssPrefixes.length; while ( i-- ) { name = cssPrefixes[ i ] + capName; if ( name in emptyStyle ) { return name; } } } // Return a property mapped along what jQuery.cssProps suggests or to // a vendor prefixed property. function finalPropName( name ) { var ret = jQuery.cssProps[ name ]; if ( !ret ) { ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; } return ret; } function setPositiveNumber( elem, value, subtract ) { // Any relative (+/-) values have already been // normalized at this point var matches = rcssNum.exec( value ); return matches ? // Guard against undefined "subtract", e.g., when used as in cssHooks Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : value; } function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { var i, val = 0; // If we already have the right measurement, avoid augmentation if ( extra === ( isBorderBox ? "border" : "content" ) ) { i = 4; // Otherwise initialize for horizontal or vertical properties } else { i = name === "width" ? 1 : 0; } for ( ; i < 4; i += 2 ) { // Both box models exclude margin, so add it if we want it if ( extra === "margin" ) { val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); } if ( isBorderBox ) { // border-box includes padding, so remove it if we want content if ( extra === "content" ) { val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); } // At this point, extra isn't border nor margin, so remove border if ( extra !== "margin" ) { val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } } else { // At this point, extra isn't content, so add padding val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); // At this point, extra isn't content nor padding, so add border if ( extra !== "padding" ) { val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } } } return val; } function getWidthOrHeight( elem, name, extra ) { // Start with computed style var valueIsBorderBox, styles = getStyles( elem ), val = curCSS( elem, name, styles ), isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; // Computed unit is not pixels. Stop here and return. if ( rnumnonpx.test( val ) ) { return val; } // Check for style in case a browser which returns unreliable values // for getComputedStyle silently falls back to the reliable elem.style valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] ); // Fall back to offsetWidth/Height when value is "auto" // This happens for inline elements with no explicit setting (gh-3571) if ( val === "auto" ) { val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; } // Normalize "", auto, and prepare for extra val = parseFloat( val ) || 0; // Use the active box-sizing model to add/subtract irrelevant styles return ( val + augmentWidthOrHeight( elem, name, extra || ( isBorderBox ? "border" : "content" ), valueIsBorderBox, styles ) ) + "px"; } jQuery.extend( { // Add in style property hooks for overriding the default // behavior of getting and setting a style property cssHooks: { opacity: { get: function( elem, computed ) { if ( computed ) { // We should always get a number back from opacity var ret = curCSS( elem, "opacity" ); return ret === "" ? "1" : ret; } } } }, // Don't automatically add "px" to these possibly-unitless properties cssNumber: { "animationIterationCount": true, "columnCount": true, "fillOpacity": true, "flexGrow": true, "flexShrink": true, "fontWeight": true, "lineHeight": true, "opacity": true, "order": true, "orphans": true, "widows": true, "zIndex": true, "zoom": true }, // Add in properties whose names you wish to fix before // setting or getting the value cssProps: { "float": "cssFloat" }, // Get and set the style property on a DOM Node style: function( elem, name, value, extra ) { // Don't set styles on text and comment nodes if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { return; } // Make sure that we're working with the right name var ret, type, hooks, origName = jQuery.camelCase( name ), isCustomProp = rcustomProp.test( name ), style = elem.style; // Make sure that we're working with the right name. We don't // want to query the value if it is a CSS custom property // since they are user-defined. if ( !isCustomProp ) { name = finalPropName( origName ); } // Gets hook for the prefixed version, then unprefixed version hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // Check if we're setting a value if ( value !== undefined ) { type = typeof value; // Convert "+=" or "-=" to relative numbers (#7345) if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { value = adjustCSS( elem, name, ret ); // Fixes bug #9237 type = "number"; } // Make sure that null and NaN values aren't set (#7116) if ( value == null || value !== value ) { return; } // If a number was passed in, add the unit (except for certain CSS properties) if ( type === "number" ) { value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); } // background-* props affect original clone's values if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { style[ name ] = "inherit"; } // If a hook was provided, use that value, otherwise just set the specified value if ( !hooks || !( "set" in hooks ) || ( value = hooks.set( elem, value, extra ) ) !== undefined ) { if ( isCustomProp ) { style.setProperty( name, value ); } else { style[ name ] = value; } } } else { // If a hook was provided get the non-computed value from there if ( hooks && "get" in hooks && ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { return ret; } // Otherwise just get the value from the style object return style[ name ]; } }, css: function( elem, name, extra, styles ) { var val, num, hooks, origName = jQuery.camelCase( name ), isCustomProp = rcustomProp.test( name ); // Make sure that we're working with the right name. We don't // want to modify the value if it is a CSS custom property // since they are user-defined. if ( !isCustomProp ) { name = finalPropName( origName ); } // Try prefixed name followed by the unprefixed name hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // If a hook was provided get the computed value from there if ( hooks && "get" in hooks ) { val = hooks.get( elem, true, extra ); } // Otherwise, if a way to get the computed value exists, use that if ( val === undefined ) { val = curCSS( elem, name, styles ); } // Convert "normal" to computed value if ( val === "normal" && name in cssNormalTransform ) { val = cssNormalTransform[ name ]; } // Make numeric if forced or a qualifier was provided and val looks numeric if ( extra === "" || extra ) { num = parseFloat( val ); return extra === true || isFinite( num ) ? num || 0 : val; } return val; } } ); jQuery.each( [ "height", "width" ], function( i, name ) { jQuery.cssHooks[ name ] = { get: function( elem, computed, extra ) { if ( computed ) { // Certain elements can have dimension info if we invisibly show them // but it must have a current display style that would benefit return rdisplayswap.test( jQuery.css( elem, "display" ) ) && // Support: Safari 8+ // Table columns in Safari have non-zero offsetWidth & zero // getBoundingClientRect().width unless display is changed. // Support: IE <=11 only // Running getBoundingClientRect on a disconnected node // in IE throws an error. ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? swap( elem, cssShow, function() { return getWidthOrHeight( elem, name, extra ); } ) : getWidthOrHeight( elem, name, extra ); } }, set: function( elem, value, extra ) { var matches, styles = extra && getStyles( elem ), subtract = extra && augmentWidthOrHeight( elem, name, extra, jQuery.css( elem, "boxSizing", false, styles ) === "border-box", styles ); // Convert to pixels if value adjustment is needed if ( subtract && ( matches = rcssNum.exec( value ) ) && ( matches[ 3 ] || "px" ) !== "px" ) { elem.style[ name ] = value; value = jQuery.css( elem, name ); } return setPositiveNumber( elem, value, subtract ); } }; } ); jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, function( elem, computed ) { if ( computed ) { return ( parseFloat( curCSS( elem, "marginLeft" ) ) || elem.getBoundingClientRect().left - swap( elem, { marginLeft: 0 }, function() { return elem.getBoundingClientRect().left; } ) ) + "px"; } } ); // These hooks are used by animate to expand properties jQuery.each( { margin: "", padding: "", border: "Width" }, function( prefix, suffix ) { jQuery.cssHooks[ prefix + suffix ] = { expand: function( value ) { var i = 0, expanded = {}, // Assumes a single number if not a string parts = typeof value === "string" ? value.split( " " ) : [ value ]; for ( ; i < 4; i++ ) { expanded[ prefix + cssExpand[ i ] + suffix ] = parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; } return expanded; } }; if ( !rmargin.test( prefix ) ) { jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; } } ); jQuery.fn.extend( { css: function( name, value ) { return access( this, function( elem, name, value ) { var styles, len, map = {}, i = 0; if ( Array.isArray( name ) ) { styles = getStyles( elem ); len = name.length; for ( ; i < len; i++ ) { map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); } return map; } return value !== undefined ? jQuery.style( elem, name, value ) : jQuery.css( elem, name ); }, name, value, arguments.length > 1 ); } } ); function Tween( elem, options, prop, end, easing ) { return new Tween.prototype.init( elem, options, prop, end, easing ); } jQuery.Tween = Tween; Tween.prototype = { constructor: Tween, init: function( elem, options, prop, end, easing, unit ) { this.elem = elem; this.prop = prop; this.easing = easing || jQuery.easing._default; this.options = options; this.start = this.now = this.cur(); this.end = end; this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); }, cur: function() { var hooks = Tween.propHooks[ this.prop ]; return hooks && hooks.get ? hooks.get( this ) : Tween.propHooks._default.get( this ); }, run: function( percent ) { var eased, hooks = Tween.propHooks[ this.prop ]; if ( this.options.duration ) { this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); } else { this.pos = eased = percent; } this.now = ( this.end - this.start ) * eased + this.start; if ( this.options.step ) { this.options.step.call( this.elem, this.now, this ); } if ( hooks && hooks.set ) { hooks.set( this ); } else { Tween.propHooks._default.set( this ); } return this; } }; Tween.prototype.init.prototype = Tween.prototype; Tween.propHooks = { _default: { get: function( tween ) { var result; // Use a property on the element directly when it is not a DOM element, // or when there is no matching style property that exists. if ( tween.elem.nodeType !== 1 || tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { return tween.elem[ tween.prop ]; } // Passing an empty string as a 3rd parameter to .css will automatically // attempt a parseFloat and fallback to a string if the parse fails. // Simple values such as "10px" are parsed to Float; // complex values such as "rotate(1rad)" are returned as-is. result = jQuery.css( tween.elem, tween.prop, "" ); // Empty strings, null, undefined and "auto" are converted to 0. return !result || result === "auto" ? 0 : result; }, set: function( tween ) { // Use step hook for back compat. // Use cssHook if its there. // Use .style if available and use plain properties where available. if ( jQuery.fx.step[ tween.prop ] ) { jQuery.fx.step[ tween.prop ]( tween ); } else if ( tween.elem.nodeType === 1 && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); } else { tween.elem[ tween.prop ] = tween.now; } } } }; // Support: IE <=9 only // Panic based approach to setting things on disconnected nodes Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { set: function( tween ) { if ( tween.elem.nodeType && tween.elem.parentNode ) { tween.elem[ tween.prop ] = tween.now; } } }; jQuery.easing = { linear: function( p ) { return p; }, swing: function( p ) { return 0.5 - Math.cos( p * Math.PI ) / 2; }, _default: "swing" }; jQuery.fx = Tween.prototype.init; // Back compat <1.8 extension point jQuery.fx.step = {}; var fxNow, inProgress, rfxtypes = /^(?:toggle|show|hide)$/, rrun = /queueHooks$/; function schedule() { if ( inProgress ) { if ( document.hidden === false && window.requestAnimationFrame ) { window.requestAnimationFrame( schedule ); } else { window.setTimeout( schedule, jQuery.fx.interval ); } jQuery.fx.tick(); } } // Animations created synchronously will run synchronously function createFxNow() { window.setTimeout( function() { fxNow = undefined; } ); return ( fxNow = jQuery.now() ); } // Generate parameters to create a standard animation function genFx( type, includeWidth ) { var which, i = 0, attrs = { height: type }; // If we include width, step value is 1 to do all cssExpand values, // otherwise step value is 2 to skip over Left and Right includeWidth = includeWidth ? 1 : 0; for ( ; i < 4; i += 2 - includeWidth ) { which = cssExpand[ i ]; attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; } if ( includeWidth ) { attrs.opacity = attrs.width = type; } return attrs; } function createTween( value, prop, animation ) { var tween, collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), index = 0, length = collection.length; for ( ; index < length; index++ ) { if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { // We're done with this property return tween; } } } function defaultPrefilter( elem, props, opts ) { var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, isBox = "width" in props || "height" in props, anim = this, orig = {}, style = elem.style, hidden = elem.nodeType && isHiddenWithinTree( elem ), dataShow = dataPriv.get( elem, "fxshow" ); // Queue-skipping animations hijack the fx hooks if ( !opts.queue ) { hooks = jQuery._queueHooks( elem, "fx" ); if ( hooks.unqueued == null ) { hooks.unqueued = 0; oldfire = hooks.empty.fire; hooks.empty.fire = function() { if ( !hooks.unqueued ) { oldfire(); } }; } hooks.unqueued++; anim.always( function() { // Ensure the complete handler is called before this completes anim.always( function() { hooks.unqueued--; if ( !jQuery.queue( elem, "fx" ).length ) { hooks.empty.fire(); } } ); } ); } // Detect show/hide animations for ( prop in props ) { value = props[ prop ]; if ( rfxtypes.test( value ) ) { delete props[ prop ]; toggle = toggle || value === "toggle"; if ( value === ( hidden ? "hide" : "show" ) ) { // Pretend to be hidden if this is a "show" and // there is still data from a stopped show/hide if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { hidden = true; // Ignore all other no-op show/hide data } else { continue; } } orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); } } // Bail out if this is a no-op like .hide().hide() propTween = !jQuery.isEmptyObject( props ); if ( !propTween && jQuery.isEmptyObject( orig ) ) { return; } // Restrict "overflow" and "display" styles during box animations if ( isBox && elem.nodeType === 1 ) { // Support: IE <=9 - 11, Edge 12 - 13 // Record all 3 overflow attributes because IE does not infer the shorthand // from identically-valued overflowX and overflowY opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; // Identify a display type, preferring old show/hide data over the CSS cascade restoreDisplay = dataShow && dataShow.display; if ( restoreDisplay == null ) { restoreDisplay = dataPriv.get( elem, "display" ); } display = jQuery.css( elem, "display" ); if ( display === "none" ) { if ( restoreDisplay ) { display = restoreDisplay; } else { // Get nonempty value(s) by temporarily forcing visibility showHide( [ elem ], true ); restoreDisplay = elem.style.display || restoreDisplay; display = jQuery.css( elem, "display" ); showHide( [ elem ] ); } } // Animate inline elements as inline-block if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { if ( jQuery.css( elem, "float" ) === "none" ) { // Restore the original display value at the end of pure show/hide animations if ( !propTween ) { anim.done( function() { style.display = restoreDisplay; } ); if ( restoreDisplay == null ) { display = style.display; restoreDisplay = display === "none" ? "" : display; } } style.display = "inline-block"; } } } if ( opts.overflow ) { style.overflow = "hidden"; anim.always( function() { style.overflow = opts.overflow[ 0 ]; style.overflowX = opts.overflow[ 1 ]; style.overflowY = opts.overflow[ 2 ]; } ); } // Implement show/hide animations propTween = false; for ( prop in orig ) { // General show/hide setup for this element animation if ( !propTween ) { if ( dataShow ) { if ( "hidden" in dataShow ) { hidden = dataShow.hidden; } } else { dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); } // Store hidden/visible for toggle so `.stop().toggle()` "reverses" if ( toggle ) { dataShow.hidden = !hidden; } // Show elements before animating them if ( hidden ) { showHide( [ elem ], true ); } /* eslint-disable no-loop-func */ anim.done( function() { /* eslint-enable no-loop-func */ // The final step of a "hide" animation is actually hiding the element if ( !hidden ) { showHide( [ elem ] ); } dataPriv.remove( elem, "fxshow" ); for ( prop in orig ) { jQuery.style( elem, prop, orig[ prop ] ); } } ); } // Per-property setup propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); if ( !( prop in dataShow ) ) { dataShow[ prop ] = propTween.start; if ( hidden ) { propTween.end = propTween.start; propTween.start = 0; } } } } function propFilter( props, specialEasing ) { var index, name, easing, value, hooks; // camelCase, specialEasing and expand cssHook pass for ( index in props ) { name = jQuery.camelCase( index ); easing = specialEasing[ name ]; value = props[ index ]; if ( Array.isArray( value ) ) { easing = value[ 1 ]; value = props[ index ] = value[ 0 ]; } if ( index !== name ) { props[ name ] = value; delete props[ index ]; } hooks = jQuery.cssHooks[ name ]; if ( hooks && "expand" in hooks ) { value = hooks.expand( value ); delete props[ name ]; // Not quite $.extend, this won't overwrite existing keys. // Reusing 'index' because we have the correct "name" for ( index in value ) { if ( !( index in props ) ) { props[ index ] = value[ index ]; specialEasing[ index ] = easing; } } } else { specialEasing[ name ] = easing; } } } function Animation( elem, properties, options ) { var result, stopped, index = 0, length = Animation.prefilters.length, deferred = jQuery.Deferred().always( function() { // Don't match elem in the :animated selector delete tick.elem; } ), tick = function() { if ( stopped ) { return false; } var currentTime = fxNow || createFxNow(), remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), // Support: Android 2.3 only // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) temp = remaining / animation.duration || 0, percent = 1 - temp, index = 0, length = animation.tweens.length; for ( ; index < length; index++ ) { animation.tweens[ index ].run( percent ); } deferred.notifyWith( elem, [ animation, percent, remaining ] ); // If there's more to do, yield if ( percent < 1 && length ) { return remaining; } // If this was an empty animation, synthesize a final progress notification if ( !length ) { deferred.notifyWith( elem, [ animation, 1, 0 ] ); } // Resolve the animation and report its conclusion deferred.resolveWith( elem, [ animation ] ); return false; }, animation = deferred.promise( { elem: elem, props: jQuery.extend( {}, properties ), opts: jQuery.extend( true, { specialEasing: {}, easing: jQuery.easing._default }, options ), originalProperties: properties, originalOptions: options, startTime: fxNow || createFxNow(), duration: options.duration, tweens: [], createTween: function( prop, end ) { var tween = jQuery.Tween( elem, animation.opts, prop, end, animation.opts.specialEasing[ prop ] || animation.opts.easing ); animation.tweens.push( tween ); return tween; }, stop: function( gotoEnd ) { var index = 0, // If we are going to the end, we want to run all the tweens // otherwise we skip this part length = gotoEnd ? animation.tweens.length : 0; if ( stopped ) { return this; } stopped = true; for ( ; index < length; index++ ) { animation.tweens[ index ].run( 1 ); } // Resolve when we played the last frame; otherwise, reject if ( gotoEnd ) { deferred.notifyWith( elem, [ animation, 1, 0 ] ); deferred.resolveWith( elem, [ animation, gotoEnd ] ); } else { deferred.rejectWith( elem, [ animation, gotoEnd ] ); } return this; } } ), props = animation.props; propFilter( props, animation.opts.specialEasing ); for ( ; index < length; index++ ) { result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); if ( result ) { if ( jQuery.isFunction( result.stop ) ) { jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = jQuery.proxy( result.stop, result ); } return result; } } jQuery.map( props, createTween, animation ); if ( jQuery.isFunction( animation.opts.start ) ) { animation.opts.start.call( elem, animation ); } // Attach callbacks from options animation .progress( animation.opts.progress ) .done( animation.opts.done, animation.opts.complete ) .fail( animation.opts.fail ) .always( animation.opts.always ); jQuery.fx.timer( jQuery.extend( tick, { elem: elem, anim: animation, queue: animation.opts.queue } ) ); return animation; } jQuery.Animation = jQuery.extend( Animation, { tweeners: { "*": [ function( prop, value ) { var tween = this.createTween( prop, value ); adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); return tween; } ] }, tweener: function( props, callback ) { if ( jQuery.isFunction( props ) ) { callback = props; props = [ "*" ]; } else { props = props.match( rnothtmlwhite ); } var prop, index = 0, length = props.length; for ( ; index < length; index++ ) { prop = props[ index ]; Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; Animation.tweeners[ prop ].unshift( callback ); } }, prefilters: [ defaultPrefilter ], prefilter: function( callback, prepend ) { if ( prepend ) { Animation.prefilters.unshift( callback ); } else { Animation.prefilters.push( callback ); } } } ); jQuery.speed = function( speed, easing, fn ) { var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { complete: fn || !fn && easing || jQuery.isFunction( speed ) && speed, duration: speed, easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing }; // Go to the end state if fx are off if ( jQuery.fx.off ) { opt.duration = 0; } else { if ( typeof opt.duration !== "number" ) { if ( opt.duration in jQuery.fx.speeds ) { opt.duration = jQuery.fx.speeds[ opt.duration ]; } else { opt.duration = jQuery.fx.speeds._default; } } } // Normalize opt.queue - true/undefined/null -> "fx" if ( opt.queue == null || opt.queue === true ) { opt.queue = "fx"; } // Queueing opt.old = opt.complete; opt.complete = function() { if ( jQuery.isFunction( opt.old ) ) { opt.old.call( this ); } if ( opt.queue ) { jQuery.dequeue( this, opt.queue ); } }; return opt; }; jQuery.fn.extend( { fadeTo: function( speed, to, easing, callback ) { // Show any hidden elements after setting opacity to 0 return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() // Animate to the value specified .end().animate( { opacity: to }, speed, easing, callback ); }, animate: function( prop, speed, easing, callback ) { var empty = jQuery.isEmptyObject( prop ), optall = jQuery.speed( speed, easing, callback ), doAnimation = function() { // Operate on a copy of prop so per-property easing won't be lost var anim = Animation( this, jQuery.extend( {}, prop ), optall ); // Empty animations, or finishing resolves immediately if ( empty || dataPriv.get( this, "finish" ) ) { anim.stop( true ); } }; doAnimation.finish = doAnimation; return empty || optall.queue === false ? this.each( doAnimation ) : this.queue( optall.queue, doAnimation ); }, stop: function( type, clearQueue, gotoEnd ) { var stopQueue = function( hooks ) { var stop = hooks.stop; delete hooks.stop; stop( gotoEnd ); }; if ( typeof type !== "string" ) { gotoEnd = clearQueue; clearQueue = type; type = undefined; } if ( clearQueue && type !== false ) { this.queue( type || "fx", [] ); } return this.each( function() { var dequeue = true, index = type != null && type + "queueHooks", timers = jQuery.timers, data = dataPriv.get( this ); if ( index ) { if ( data[ index ] && data[ index ].stop ) { stopQueue( data[ index ] ); } } else { for ( index in data ) { if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { stopQueue( data[ index ] ); } } } for ( index = timers.length; index--; ) { if ( timers[ index ].elem === this && ( type == null || timers[ index ].queue === type ) ) { timers[ index ].anim.stop( gotoEnd ); dequeue = false; timers.splice( index, 1 ); } } // Start the next in the queue if the last step wasn't forced. // Timers currently will call their complete callbacks, which // will dequeue but only if they were gotoEnd. if ( dequeue || !gotoEnd ) { jQuery.dequeue( this, type ); } } ); }, finish: function( type ) { if ( type !== false ) { type = type || "fx"; } return this.each( function() { var index, data = dataPriv.get( this ), queue = data[ type + "queue" ], hooks = data[ type + "queueHooks" ], timers = jQuery.timers, length = queue ? queue.length : 0; // Enable finishing flag on private data data.finish = true; // Empty the queue first jQuery.queue( this, type, [] ); if ( hooks && hooks.stop ) { hooks.stop.call( this, true ); } // Look for any active animations, and finish them for ( index = timers.length; index--; ) { if ( timers[ index ].elem === this && timers[ index ].queue === type ) { timers[ index ].anim.stop( true ); timers.splice( index, 1 ); } } // Look for any animations in the old queue and finish them for ( index = 0; index < length; index++ ) { if ( queue[ index ] && queue[ index ].finish ) { queue[ index ].finish.call( this ); } } // Turn off finishing flag delete data.finish; } ); } } ); jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { var cssFn = jQuery.fn[ name ]; jQuery.fn[ name ] = function( speed, easing, callback ) { return speed == null || typeof speed === "boolean" ? cssFn.apply( this, arguments ) : this.animate( genFx( name, true ), speed, easing, callback ); }; } ); // Generate shortcuts for custom animations jQuery.each( { slideDown: genFx( "show" ), slideUp: genFx( "hide" ), slideToggle: genFx( "toggle" ), fadeIn: { opacity: "show" }, fadeOut: { opacity: "hide" }, fadeToggle: { opacity: "toggle" } }, function( name, props ) { jQuery.fn[ name ] = function( speed, easing, callback ) { return this.animate( props, speed, easing, callback ); }; } ); jQuery.timers = []; jQuery.fx.tick = function() { var timer, i = 0, timers = jQuery.timers; fxNow = jQuery.now(); for ( ; i < timers.length; i++ ) { timer = timers[ i ]; // Run the timer and safely remove it when done (allowing for external removal) if ( !timer() && timers[ i ] === timer ) { timers.splice( i--, 1 ); } } if ( !timers.length ) { jQuery.fx.stop(); } fxNow = undefined; }; jQuery.fx.timer = function( timer ) { jQuery.timers.push( timer ); jQuery.fx.start(); }; jQuery.fx.interval = 13; jQuery.fx.start = function() { if ( inProgress ) { return; } inProgress = true; schedule(); }; jQuery.fx.stop = function() { inProgress = null; }; jQuery.fx.speeds = { slow: 600, fast: 200, // Default speed _default: 400 }; // Based off of the plugin by Clint Helfers, with permission. // https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ jQuery.fn.delay = function( time, type ) { time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; type = type || "fx"; return this.queue( type, function( next, hooks ) { var timeout = window.setTimeout( next, time ); hooks.stop = function() { window.clearTimeout( timeout ); }; } ); }; ( function() { var input = document.createElement( "input" ), select = document.createElement( "select" ), opt = select.appendChild( document.createElement( "option" ) ); input.type = "checkbox"; // Support: Android <=4.3 only // Default value for a checkbox should be "on" support.checkOn = input.value !== ""; // Support: IE <=11 only // Must access selectedIndex to make default options select support.optSelected = opt.selected; // Support: IE <=11 only // An input loses its value after becoming a radio input = document.createElement( "input" ); input.value = "t"; input.type = "radio"; support.radioValue = input.value === "t"; } )(); var boolHook, attrHandle = jQuery.expr.attrHandle; jQuery.fn.extend( { attr: function( name, value ) { return access( this, jQuery.attr, name, value, arguments.length > 1 ); }, removeAttr: function( name ) { return this.each( function() { jQuery.removeAttr( this, name ); } ); } } ); jQuery.extend( { attr: function( elem, name, value ) { var ret, hooks, nType = elem.nodeType; // Don't get/set attributes on text, comment and attribute nodes if ( nType === 3 || nType === 8 || nType === 2 ) { return; } // Fallback to prop when attributes are not supported if ( typeof elem.getAttribute === "undefined" ) { return jQuery.prop( elem, name, value ); } // Attribute hooks are determined by the lowercase version // Grab necessary hook if one is defined if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { hooks = jQuery.attrHooks[ name.toLowerCase() ] || ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); } if ( value !== undefined ) { if ( value === null ) { jQuery.removeAttr( elem, name ); return; } if ( hooks && "set" in hooks && ( ret = hooks.set( elem, value, name ) ) !== undefined ) { return ret; } elem.setAttribute( name, value + "" ); return value; } if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { return ret; } ret = jQuery.find.attr( elem, name ); // Non-existent attributes return null, we normalize to undefined return ret == null ? undefined : ret; }, attrHooks: { type: { set: function( elem, value ) { if ( !support.radioValue && value === "radio" && nodeName( elem, "input" ) ) { var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { elem.value = val; } return value; } } } }, removeAttr: function( elem, value ) { var name, i = 0, // Attribute names can contain non-HTML whitespace characters // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 attrNames = value && value.match( rnothtmlwhite ); if ( attrNames && elem.nodeType === 1 ) { while ( ( name = attrNames[ i++ ] ) ) { elem.removeAttribute( name ); } } } } ); // Hooks for boolean attributes boolHook = { set: function( elem, value, name ) { if ( value === false ) { // Remove boolean attributes when set to false jQuery.removeAttr( elem, name ); } else { elem.setAttribute( name, name ); } return name; } }; jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { var getter = attrHandle[ name ] || jQuery.find.attr; attrHandle[ name ] = function( elem, name, isXML ) { var ret, handle, lowercaseName = name.toLowerCase(); if ( !isXML ) { // Avoid an infinite loop by temporarily removing this function from the getter handle = attrHandle[ lowercaseName ]; attrHandle[ lowercaseName ] = ret; ret = getter( elem, name, isXML ) != null ? lowercaseName : null; attrHandle[ lowercaseName ] = handle; } return ret; }; } ); var rfocusable = /^(?:input|select|textarea|button)$/i, rclickable = /^(?:a|area)$/i; jQuery.fn.extend( { prop: function( name, value ) { return access( this, jQuery.prop, name, value, arguments.length > 1 ); }, removeProp: function( name ) { return this.each( function() { delete this[ jQuery.propFix[ name ] || name ]; } ); } } ); jQuery.extend( { prop: function( elem, name, value ) { var ret, hooks, nType = elem.nodeType; // Don't get/set properties on text, comment and attribute nodes if ( nType === 3 || nType === 8 || nType === 2 ) { return; } if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { // Fix name and attach hooks name = jQuery.propFix[ name ] || name; hooks = jQuery.propHooks[ name ]; } if ( value !== undefined ) { if ( hooks && "set" in hooks && ( ret = hooks.set( elem, value, name ) ) !== undefined ) { return ret; } return ( elem[ name ] = value ); } if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { return ret; } return elem[ name ]; }, propHooks: { tabIndex: { get: function( elem ) { // Support: IE <=9 - 11 only // elem.tabIndex doesn't always return the // correct value when it hasn't been explicitly set // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ // Use proper attribute retrieval(#12072) var tabindex = jQuery.find.attr( elem, "tabindex" ); if ( tabindex ) { return parseInt( tabindex, 10 ); } if ( rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ) { return 0; } return -1; } } }, propFix: { "for": "htmlFor", "class": "className" } } ); // Support: IE <=11 only // Accessing the selectedIndex property // forces the browser to respect setting selected // on the option // The getter ensures a default option is selected // when in an optgroup // eslint rule "no-unused-expressions" is disabled for this code // since it considers such accessions noop if ( !support.optSelected ) { jQuery.propHooks.selected = { get: function( elem ) { /* eslint no-unused-expressions: "off" */ var parent = elem.parentNode; if ( parent && parent.parentNode ) { parent.parentNode.selectedIndex; } return null; }, set: function( elem ) { /* eslint no-unused-expressions: "off" */ var parent = elem.parentNode; if ( parent ) { parent.selectedIndex; if ( parent.parentNode ) { parent.parentNode.selectedIndex; } } } }; } jQuery.each( [ "tabIndex", "readOnly", "maxLength", "cellSpacing", "cellPadding", "rowSpan", "colSpan", "useMap", "frameBorder", "contentEditable" ], function() { jQuery.propFix[ this.toLowerCase() ] = this; } ); // Strip and collapse whitespace according to HTML spec // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace function stripAndCollapse( value ) { var tokens = value.match( rnothtmlwhite ) || []; return tokens.join( " " ); } function getClass( elem ) { return elem.getAttribute && elem.getAttribute( "class" ) || ""; } jQuery.fn.extend( { addClass: function( value ) { var classes, elem, cur, curValue, clazz, j, finalValue, i = 0; if ( jQuery.isFunction( value ) ) { return this.each( function( j ) { jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); } ); } if ( typeof value === "string" && value ) { classes = value.match( rnothtmlwhite ) || []; while ( ( elem = this[ i++ ] ) ) { curValue = getClass( elem ); cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); if ( cur ) { j = 0; while ( ( clazz = classes[ j++ ] ) ) { if ( cur.indexOf( " " + clazz + " " ) < 0 ) { cur += clazz + " "; } } // Only assign if different to avoid unneeded rendering. finalValue = stripAndCollapse( cur ); if ( curValue !== finalValue ) { elem.setAttribute( "class", finalValue ); } } } } return this; }, removeClass: function( value ) { var classes, elem, cur, curValue, clazz, j, finalValue, i = 0; if ( jQuery.isFunction( value ) ) { return this.each( function( j ) { jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); } ); } if ( !arguments.length ) { return this.attr( "class", "" ); } if ( typeof value === "string" && value ) { classes = value.match( rnothtmlwhite ) || []; while ( ( elem = this[ i++ ] ) ) { curValue = getClass( elem ); // This expression is here for better compressibility (see addClass) cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); if ( cur ) { j = 0; while ( ( clazz = classes[ j++ ] ) ) { // Remove *all* instances while ( cur.indexOf( " " + clazz + " " ) > -1 ) { cur = cur.replace( " " + clazz + " ", " " ); } } // Only assign if different to avoid unneeded rendering. finalValue = stripAndCollapse( cur ); if ( curValue !== finalValue ) { elem.setAttribute( "class", finalValue ); } } } } return this; }, toggleClass: function( value, stateVal ) { var type = typeof value; if ( typeof stateVal === "boolean" && type === "string" ) { return stateVal ? this.addClass( value ) : this.removeClass( value ); } if ( jQuery.isFunction( value ) ) { return this.each( function( i ) { jQuery( this ).toggleClass( value.call( this, i, getClass( this ), stateVal ), stateVal ); } ); } return this.each( function() { var className, i, self, classNames; if ( type === "string" ) { // Toggle individual class names i = 0; self = jQuery( this ); classNames = value.match( rnothtmlwhite ) || []; while ( ( className = classNames[ i++ ] ) ) { // Check each className given, space separated list if ( self.hasClass( className ) ) { self.removeClass( className ); } else { self.addClass( className ); } } // Toggle whole class name } else if ( value === undefined || type === "boolean" ) { className = getClass( this ); if ( className ) { // Store className if set dataPriv.set( this, "__className__", className ); } // If the element has a class name or if we're passed `false`, // then remove the whole classname (if there was one, the above saved it). // Otherwise bring back whatever was previously saved (if anything), // falling back to the empty string if nothing was stored. if ( this.setAttribute ) { this.setAttribute( "class", className || value === false ? "" : dataPriv.get( this, "__className__" ) || "" ); } } } ); }, hasClass: function( selector ) { var className, elem, i = 0; className = " " + selector + " "; while ( ( elem = this[ i++ ] ) ) { if ( elem.nodeType === 1 && ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { return true; } } return false; } } ); var rreturn = /\r/g; jQuery.fn.extend( { val: function( value ) { var hooks, ret, isFunction, elem = this[ 0 ]; if ( !arguments.length ) { if ( elem ) { hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; if ( hooks && "get" in hooks && ( ret = hooks.get( elem, "value" ) ) !== undefined ) { return ret; } ret = elem.value; // Handle most common string cases if ( typeof ret === "string" ) { return ret.replace( rreturn, "" ); } // Handle cases where value is null/undef or number return ret == null ? "" : ret; } return; } isFunction = jQuery.isFunction( value ); return this.each( function( i ) { var val; if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { val = value.call( this, i, jQuery( this ).val() ); } else { val = value; } // Treat null/undefined as ""; convert numbers to string if ( val == null ) { val = ""; } else if ( typeof val === "number" ) { val += ""; } else if ( Array.isArray( val ) ) { val = jQuery.map( val, function( value ) { return value == null ? "" : value + ""; } ); } hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; // If set returns undefined, fall back to normal setting if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } } ); } } ); jQuery.extend( { valHooks: { option: { get: function( elem ) { var val = jQuery.find.attr( elem, "value" ); return val != null ? val : // Support: IE <=10 - 11 only // option.text throws exceptions (#14686, #14858) // Strip and collapse whitespace // https://html.spec.whatwg.org/#strip-and-collapse-whitespace stripAndCollapse( jQuery.text( elem ) ); } }, select: { get: function( elem ) { var value, option, i, options = elem.options, index = elem.selectedIndex, one = elem.type === "select-one", values = one ? null : [], max = one ? index + 1 : options.length; if ( index < 0 ) { i = max; } else { i = one ? index : 0; } // Loop through all the selected options for ( ; i < max; i++ ) { option = options[ i ]; // Support: IE <=9 only // IE8-9 doesn't update selected after form reset (#2551) if ( ( option.selected || i === index ) && // Don't return options that are disabled or in a disabled optgroup !option.disabled && ( !option.parentNode.disabled || !nodeName( option.parentNode, "optgroup" ) ) ) { // Get the specific value for the option value = jQuery( option ).val(); // We don't need an array for one selects if ( one ) { return value; } // Multi-Selects return an array values.push( value ); } } return values; }, set: function( elem, value ) { var optionSet, option, options = elem.options, values = jQuery.makeArray( value ), i = options.length; while ( i-- ) { option = options[ i ]; /* eslint-disable no-cond-assign */ if ( option.selected = jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 ) { optionSet = true; } /* eslint-enable no-cond-assign */ } // Force browsers to behave consistently when non-matching value is set if ( !optionSet ) { elem.selectedIndex = -1; } return values; } } } } ); // Radios and checkboxes getter/setter jQuery.each( [ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = { set: function( elem, value ) { if ( Array.isArray( value ) ) { return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); } } }; if ( !support.checkOn ) { jQuery.valHooks[ this ].get = function( elem ) { return elem.getAttribute( "value" ) === null ? "on" : elem.value; }; } } ); // Return jQuery for attributes-only inclusion var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; jQuery.extend( jQuery.event, { trigger: function( event, data, elem, onlyHandlers ) { var i, cur, tmp, bubbleType, ontype, handle, special, eventPath = [ elem || document ], type = hasOwn.call( event, "type" ) ? event.type : event, namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; cur = tmp = elem = elem || document; // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // focus/blur morphs to focusin/out; ensure we're not firing them right now if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } if ( type.indexOf( "." ) > -1 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split( "." ); type = namespaces.shift(); namespaces.sort(); } ontype = type.indexOf( ":" ) < 0 && "on" + type; // Caller can pass in a jQuery.Event object, Object, or just an event type string event = event[ jQuery.expando ] ? event : new jQuery.Event( type, typeof event === "object" && event ); // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) event.isTrigger = onlyHandlers ? 2 : 3; event.namespace = namespaces.join( "." ); event.rnamespace = event.namespace ? new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : null; // Clean up the event in case it is being reused event.result = undefined; if ( !event.target ) { event.target = elem; } // Clone any incoming data and prepend the event, creating the handler arg list data = data == null ? [ event ] : jQuery.makeArray( data, [ event ] ); // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { return; } // Determine event propagation path in advance, per W3C events spec (#9951) // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { bubbleType = special.delegateType || type; if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } for ( ; cur; cur = cur.parentNode ) { eventPath.push( cur ); tmp = cur; } // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( tmp === ( elem.ownerDocument || document ) ) { eventPath.push( tmp.defaultView || tmp.parentWindow || window ); } } // Fire handlers on the event path i = 0; while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { event.type = i > 1 ? bubbleType : special.bindType || type; // jQuery handler handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && dataPriv.get( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); } // Native handler handle = ontype && cur[ ontype ]; if ( handle && handle.apply && acceptData( cur ) ) { event.result = handle.apply( cur, data ); if ( event.result === false ) { event.preventDefault(); } } } event.type = type; // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( ( !special._default || special._default.apply( eventPath.pop(), data ) === false ) && acceptData( elem ) ) { // Call a native DOM method on the target with the same name as the event. // Don't do default actions on window, that's where global variables be (#6170) if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; if ( tmp ) { elem[ ontype ] = null; } // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; elem[ type ](); jQuery.event.triggered = undefined; if ( tmp ) { elem[ ontype ] = tmp; } } } } return event.result; }, // Piggyback on a donor event to simulate a different one // Used only for `focus(in | out)` events simulate: function( type, elem, event ) { var e = jQuery.extend( new jQuery.Event(), event, { type: type, isSimulated: true } ); jQuery.event.trigger( e, null, elem ); } } ); jQuery.fn.extend( { trigger: function( type, data ) { return this.each( function() { jQuery.event.trigger( type, data, this ); } ); }, triggerHandler: function( type, data ) { var elem = this[ 0 ]; if ( elem ) { return jQuery.event.trigger( type, data, elem, true ); } } } ); jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup contextmenu" ).split( " " ), function( i, name ) { // Handle event binding jQuery.fn[ name ] = function( data, fn ) { return arguments.length > 0 ? this.on( name, null, data, fn ) : this.trigger( name ); }; } ); jQuery.fn.extend( { hover: function( fnOver, fnOut ) { return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); } } ); support.focusin = "onfocusin" in window; // Support: Firefox <=44 // Firefox doesn't have focus(in | out) events // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 // // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 // focus(in | out) events fire after focus & blur events, // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 if ( !support.focusin ) { jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { // Attach a single capturing handler on the document while someone wants focusin/focusout var handler = function( event ) { jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); }; jQuery.event.special[ fix ] = { setup: function() { var doc = this.ownerDocument || this, attaches = dataPriv.access( doc, fix ); if ( !attaches ) { doc.addEventListener( orig, handler, true ); } dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); }, teardown: function() { var doc = this.ownerDocument || this, attaches = dataPriv.access( doc, fix ) - 1; if ( !attaches ) { doc.removeEventListener( orig, handler, true ); dataPriv.remove( doc, fix ); } else { dataPriv.access( doc, fix, attaches ); } } }; } ); } var location = window.location; var nonce = jQuery.now(); var rquery = ( /\?/ ); // Cross-browser xml parsing jQuery.parseXML = function( data ) { var xml; if ( !data || typeof data !== "string" ) { return null; } // Support: IE 9 - 11 only // IE throws on parseFromString with invalid input. try { xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); } catch ( e ) { xml = undefined; } if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { jQuery.error( "Invalid XML: " + data ); } return xml; }; var rbracket = /\[\]$/, rCRLF = /\r?\n/g, rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, rsubmittable = /^(?:input|select|textarea|keygen)/i; function buildParams( prefix, obj, traditional, add ) { var name; if ( Array.isArray( obj ) ) { // Serialize array item. jQuery.each( obj, function( i, v ) { if ( traditional || rbracket.test( prefix ) ) { // Treat each array item as a scalar. add( prefix, v ); } else { // Item is non-scalar (array or object), encode its numeric index. buildParams( prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", v, traditional, add ); } } ); } else if ( !traditional && jQuery.type( obj ) === "object" ) { // Serialize object item. for ( name in obj ) { buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); } } else { // Serialize scalar item. add( prefix, obj ); } } // Serialize an array of form elements or a set of // key/values into a query string jQuery.param = function( a, traditional ) { var prefix, s = [], add = function( key, valueOrFunction ) { // If value is a function, invoke it and use its return value var value = jQuery.isFunction( valueOrFunction ) ? valueOrFunction() : valueOrFunction; s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value == null ? "" : value ); }; // If an array was passed in, assume that it is an array of form elements. if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { // Serialize the form elements jQuery.each( a, function() { add( this.name, this.value ); } ); } else { // If traditional, encode the "old" way (the way 1.3.2 or older // did it), otherwise encode params recursively. for ( prefix in a ) { buildParams( prefix, a[ prefix ], traditional, add ); } } // Return the resulting serialization return s.join( "&" ); }; jQuery.fn.extend( { serialize: function() { return jQuery.param( this.serializeArray() ); }, serializeArray: function() { return this.map( function() { // Can add propHook for "elements" to filter or add form elements var elements = jQuery.prop( this, "elements" ); return elements ? jQuery.makeArray( elements ) : this; } ) .filter( function() { var type = this.type; // Use .is( ":disabled" ) so that fieldset[disabled] works return this.name && !jQuery( this ).is( ":disabled" ) && rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && ( this.checked || !rcheckableType.test( type ) ); } ) .map( function( i, elem ) { var val = jQuery( this ).val(); if ( val == null ) { return null; } if ( Array.isArray( val ) ) { return jQuery.map( val, function( val ) { return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; } ); } return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; } ).get(); } } ); var r20 = /%20/g, rhash = /#.*$/, rantiCache = /([?&])_=[^&]*/, rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, // #7653, #8125, #8152: local protocol detection rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, /* Prefilters * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) * 2) These are called: * - BEFORE asking for a transport * - AFTER param serialization (s.data is a string if s.processData is true) * 3) key is the dataType * 4) the catchall symbol "*" can be used * 5) execution will start with transport dataType and THEN continue down to "*" if needed */ prefilters = {}, /* Transports bindings * 1) key is the dataType * 2) the catchall symbol "*" can be used * 3) selection will start with transport dataType and THEN go to "*" if needed */ transports = {}, // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression allTypes = "*/".concat( "*" ), // Anchor tag for parsing the document origin originAnchor = document.createElement( "a" ); originAnchor.href = location.href; // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { // dataTypeExpression is optional and defaults to "*" return function( dataTypeExpression, func ) { if ( typeof dataTypeExpression !== "string" ) { func = dataTypeExpression; dataTypeExpression = "*"; } var dataType, i = 0, dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; if ( jQuery.isFunction( func ) ) { // For each dataType in the dataTypeExpression while ( ( dataType = dataTypes[ i++ ] ) ) { // Prepend if requested if ( dataType[ 0 ] === "+" ) { dataType = dataType.slice( 1 ) || "*"; ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); // Otherwise append } else { ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); } } } }; } // Base inspection function for prefilters and transports function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { var inspected = {}, seekingTransport = ( structure === transports ); function inspect( dataType ) { var selected; inspected[ dataType ] = true; jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) { options.dataTypes.unshift( dataTypeOrTransport ); inspect( dataTypeOrTransport ); return false; } else if ( seekingTransport ) { return !( selected = dataTypeOrTransport ); } } ); return selected; } return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); } // A special extend for ajax options // that takes "flat" options (not to be deep extended) // Fixes #9887 function ajaxExtend( target, src ) { var key, deep, flatOptions = jQuery.ajaxSettings.flatOptions || {}; for ( key in src ) { if ( src[ key ] !== undefined ) { ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; } } if ( deep ) { jQuery.extend( true, target, deep ); } return target; } /* Handles responses to an ajax request: * - finds the right dataType (mediates between content-type and expected dataType) * - returns the corresponding response */ function ajaxHandleResponses( s, jqXHR, responses ) { var ct, type, finalDataType, firstDataType, contents = s.contents, dataTypes = s.dataTypes; // Remove auto dataType and get content-type in the process while ( dataTypes[ 0 ] === "*" ) { dataTypes.shift(); if ( ct === undefined ) { ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); } } // Check if we're dealing with a known content-type if ( ct ) { for ( type in contents ) { if ( contents[ type ] && contents[ type ].test( ct ) ) { dataTypes.unshift( type ); break; } } } // Check to see if we have a response for the expected dataType if ( dataTypes[ 0 ] in responses ) { finalDataType = dataTypes[ 0 ]; } else { // Try convertible dataTypes for ( type in responses ) { if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { finalDataType = type; break; } if ( !firstDataType ) { firstDataType = type; } } // Or just use first one finalDataType = finalDataType || firstDataType; } // If we found a dataType // We add the dataType to the list if needed // and return the corresponding response if ( finalDataType ) { if ( finalDataType !== dataTypes[ 0 ] ) { dataTypes.unshift( finalDataType ); } return responses[ finalDataType ]; } } /* Chain conversions given the request and the original response * Also sets the responseXXX fields on the jqXHR instance */ function ajaxConvert( s, response, jqXHR, isSuccess ) { var conv2, current, conv, tmp, prev, converters = {}, // Work with a copy of dataTypes in case we need to modify it for conversion dataTypes = s.dataTypes.slice(); // Create converters map with lowercased keys if ( dataTypes[ 1 ] ) { for ( conv in s.converters ) { converters[ conv.toLowerCase() ] = s.converters[ conv ]; } } current = dataTypes.shift(); // Convert to each sequential dataType while ( current ) { if ( s.responseFields[ current ] ) { jqXHR[ s.responseFields[ current ] ] = response; } // Apply the dataFilter if provided if ( !prev && isSuccess && s.dataFilter ) { response = s.dataFilter( response, s.dataType ); } prev = current; current = dataTypes.shift(); if ( current ) { // There's only work to do if current dataType is non-auto if ( current === "*" ) { current = prev; // Convert response if prev dataType is non-auto and differs from current } else if ( prev !== "*" && prev !== current ) { // Seek a direct converter conv = converters[ prev + " " + current ] || converters[ "* " + current ]; // If none found, seek a pair if ( !conv ) { for ( conv2 in converters ) { // If conv2 outputs current tmp = conv2.split( " " ); if ( tmp[ 1 ] === current ) { // If prev can be converted to accepted input conv = converters[ prev + " " + tmp[ 0 ] ] || converters[ "* " + tmp[ 0 ] ]; if ( conv ) { // Condense equivalence converters if ( conv === true ) { conv = converters[ conv2 ]; // Otherwise, insert the intermediate dataType } else if ( converters[ conv2 ] !== true ) { current = tmp[ 0 ]; dataTypes.unshift( tmp[ 1 ] ); } break; } } } } // Apply converter (if not an equivalence) if ( conv !== true ) { // Unless errors are allowed to bubble, catch and return them if ( conv && s.throws ) { response = conv( response ); } else { try { response = conv( response ); } catch ( e ) { return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; } } } } } } return { state: "success", data: response }; } jQuery.extend( { // Counter for holding the number of active queries active: 0, // Last-Modified header cache for next request lastModified: {}, etag: {}, ajaxSettings: { url: location.href, type: "GET", isLocal: rlocalProtocol.test( location.protocol ), global: true, processData: true, async: true, contentType: "application/x-www-form-urlencoded; charset=UTF-8", /* timeout: 0, data: null, dataType: null, username: null, password: null, cache: null, throws: false, traditional: false, headers: {}, */ accepts: { "*": allTypes, text: "text/plain", html: "text/html", xml: "application/xml, text/xml", json: "application/json, text/javascript" }, contents: { xml: /\bxml\b/, html: /\bhtml/, json: /\bjson\b/ }, responseFields: { xml: "responseXML", text: "responseText", json: "responseJSON" }, // Data converters // Keys separate source (or catchall "*") and destination types with a single space converters: { // Convert anything to text "* text": String, // Text to html (true = no transformation) "text html": true, // Evaluate text as a json expression "text json": JSON.parse, // Parse text as xml "text xml": jQuery.parseXML }, // For options that shouldn't be deep extended: // you can add your own custom options here if // and when you create one that shouldn't be // deep extended (see ajaxExtend) flatOptions: { url: true, context: true } }, // Creates a full fledged settings object into target // with both ajaxSettings and settings fields. // If target is omitted, writes into ajaxSettings. ajaxSetup: function( target, settings ) { return settings ? // Building a settings object ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : // Extending ajaxSettings ajaxExtend( jQuery.ajaxSettings, target ); }, ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), ajaxTransport: addToPrefiltersOrTransports( transports ), // Main method ajax: function( url, options ) { // If url is an object, simulate pre-1.5 signature if ( typeof url === "object" ) { options = url; url = undefined; } // Force options to be an object options = options || {}; var transport, // URL without anti-cache param cacheURL, // Response headers responseHeadersString, responseHeaders, // timeout handle timeoutTimer, // Url cleanup var urlAnchor, // Request state (becomes false upon send and true upon completion) completed, // To know if global events are to be dispatched fireGlobals, // Loop variable i, // uncached part of the url uncached, // Create the final options object s = jQuery.ajaxSetup( {}, options ), // Callbacks context callbackContext = s.context || s, // Context for global events is callbackContext if it is a DOM node or jQuery collection globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ? jQuery( callbackContext ) : jQuery.event, // Deferreds deferred = jQuery.Deferred(), completeDeferred = jQuery.Callbacks( "once memory" ), // Status-dependent callbacks statusCode = s.statusCode || {}, // Headers (they are sent all at once) requestHeaders = {}, requestHeadersNames = {}, // Default abort message strAbort = "canceled", // Fake xhr jqXHR = { readyState: 0, // Builds headers hashtable if needed getResponseHeader: function( key ) { var match; if ( completed ) { if ( !responseHeaders ) { responseHeaders = {}; while ( ( match = rheaders.exec( responseHeadersString ) ) ) { responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; } } match = responseHeaders[ key.toLowerCase() ]; } return match == null ? null : match; }, // Raw string getAllResponseHeaders: function() { return completed ? responseHeadersString : null; }, // Caches the header setRequestHeader: function( name, value ) { if ( completed == null ) { name = requestHeadersNames[ name.toLowerCase() ] = requestHeadersNames[ name.toLowerCase() ] || name; requestHeaders[ name ] = value; } return this; }, // Overrides response content-type header overrideMimeType: function( type ) { if ( completed == null ) { s.mimeType = type; } return this; }, // Status-dependent callbacks statusCode: function( map ) { var code; if ( map ) { if ( completed ) { // Execute the appropriate callbacks jqXHR.always( map[ jqXHR.status ] ); } else { // Lazy-add the new callbacks in a way that preserves old ones for ( code in map ) { statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; } } } return this; }, // Cancel the request abort: function( statusText ) { var finalText = statusText || strAbort; if ( transport ) { transport.abort( finalText ); } done( 0, finalText ); return this; } }; // Attach deferreds deferred.promise( jqXHR ); // Add protocol if not provided (prefilters might expect it) // Handle falsy url in the settings object (#10093: consistency with old signature) // We also use the url parameter if available s.url = ( ( url || s.url || location.href ) + "" ) .replace( rprotocol, location.protocol + "//" ); // Alias method option to type as per ticket #12004 s.type = options.method || options.type || s.method || s.type; // Extract dataTypes list s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; // A cross-domain request is in order when the origin doesn't match the current origin. if ( s.crossDomain == null ) { urlAnchor = document.createElement( "a" ); // Support: IE <=8 - 11, Edge 12 - 13 // IE throws exception on accessing the href property if url is malformed, // e.g. http://example.com:80x/ try { urlAnchor.href = s.url; // Support: IE <=8 - 11 only // Anchor's host property isn't correctly set when s.url is relative urlAnchor.href = urlAnchor.href; s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== urlAnchor.protocol + "//" + urlAnchor.host; } catch ( e ) { // If there is an error parsing the URL, assume it is crossDomain, // it can be rejected by the transport if it is invalid s.crossDomain = true; } } // Convert data if not already a string if ( s.data && s.processData && typeof s.data !== "string" ) { s.data = jQuery.param( s.data, s.traditional ); } // Apply prefilters inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); // If request was aborted inside a prefilter, stop there if ( completed ) { return jqXHR; } // We can fire global events as of now if asked to // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) fireGlobals = jQuery.event && s.global; // Watch for a new set of requests if ( fireGlobals && jQuery.active++ === 0 ) { jQuery.event.trigger( "ajaxStart" ); } // Uppercase the type s.type = s.type.toUpperCase(); // Determine if request has content s.hasContent = !rnoContent.test( s.type ); // Save the URL in case we're toying with the If-Modified-Since // and/or If-None-Match header later on // Remove hash to simplify url manipulation cacheURL = s.url.replace( rhash, "" ); // More options handling for requests with no content if ( !s.hasContent ) { // Remember the hash so we can put it back uncached = s.url.slice( cacheURL.length ); // If data is available, append data to url if ( s.data ) { cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; // #9682: remove data so that it's not used in an eventual retry delete s.data; } // Add or update anti-cache param if needed if ( s.cache === false ) { cacheURL = cacheURL.replace( rantiCache, "$1" ); uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; } // Put hash and anti-cache on the URL that will be requested (gh-1732) s.url = cacheURL + uncached; // Change '%20' to '+' if this is encoded form body content (gh-2658) } else if ( s.data && s.processData && ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { s.data = s.data.replace( r20, "+" ); } // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { if ( jQuery.lastModified[ cacheURL ] ) { jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); } if ( jQuery.etag[ cacheURL ] ) { jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); } } // Set the correct header, if data is being sent if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { jqXHR.setRequestHeader( "Content-Type", s.contentType ); } // Set the Accepts header for the server, depending on the dataType jqXHR.setRequestHeader( "Accept", s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? s.accepts[ s.dataTypes[ 0 ] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : s.accepts[ "*" ] ); // Check for headers option for ( i in s.headers ) { jqXHR.setRequestHeader( i, s.headers[ i ] ); } // Allow custom headers/mimetypes and early abort if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { // Abort if not done already and return return jqXHR.abort(); } // Aborting is no longer a cancellation strAbort = "abort"; // Install callbacks on deferreds completeDeferred.add( s.complete ); jqXHR.done( s.success ); jqXHR.fail( s.error ); // Get transport transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); // If no transport, we auto-abort if ( !transport ) { done( -1, "No Transport" ); } else { jqXHR.readyState = 1; // Send global event if ( fireGlobals ) { globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); } // If request was aborted inside ajaxSend, stop there if ( completed ) { return jqXHR; } // Timeout if ( s.async && s.timeout > 0 ) { timeoutTimer = window.setTimeout( function() { jqXHR.abort( "timeout" ); }, s.timeout ); } try { completed = false; transport.send( requestHeaders, done ); } catch ( e ) { // Rethrow post-completion exceptions if ( completed ) { throw e; } // Propagate others as results done( -1, e ); } } // Callback for when everything is done function done( status, nativeStatusText, responses, headers ) { var isSuccess, success, error, response, modified, statusText = nativeStatusText; // Ignore repeat invocations if ( completed ) { return; } completed = true; // Clear timeout if it exists if ( timeoutTimer ) { window.clearTimeout( timeoutTimer ); } // Dereference transport for early garbage collection // (no matter how long the jqXHR object will be used) transport = undefined; // Cache response headers responseHeadersString = headers || ""; // Set readyState jqXHR.readyState = status > 0 ? 4 : 0; // Determine if successful isSuccess = status >= 200 && status < 300 || status === 304; // Get response data if ( responses ) { response = ajaxHandleResponses( s, jqXHR, responses ); } // Convert no matter what (that way responseXXX fields are always set) response = ajaxConvert( s, response, jqXHR, isSuccess ); // If successful, handle type chaining if ( isSuccess ) { // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { modified = jqXHR.getResponseHeader( "Last-Modified" ); if ( modified ) { jQuery.lastModified[ cacheURL ] = modified; } modified = jqXHR.getResponseHeader( "etag" ); if ( modified ) { jQuery.etag[ cacheURL ] = modified; } } // if no content if ( status === 204 || s.type === "HEAD" ) { statusText = "nocontent"; // if not modified } else if ( status === 304 ) { statusText = "notmodified"; // If we have data, let's convert it } else { statusText = response.state; success = response.data; error = response.error; isSuccess = !error; } } else { // Extract error from statusText and normalize for non-aborts error = statusText; if ( status || !statusText ) { statusText = "error"; if ( status < 0 ) { status = 0; } } } // Set data for the fake xhr object jqXHR.status = status; jqXHR.statusText = ( nativeStatusText || statusText ) + ""; // Success/Error if ( isSuccess ) { deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); } else { deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); } // Status-dependent callbacks jqXHR.statusCode( statusCode ); statusCode = undefined; if ( fireGlobals ) { globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", [ jqXHR, s, isSuccess ? success : error ] ); } // Complete completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); if ( fireGlobals ) { globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); // Handle the global AJAX counter if ( !( --jQuery.active ) ) { jQuery.event.trigger( "ajaxStop" ); } } } return jqXHR; }, getJSON: function( url, data, callback ) { return jQuery.get( url, data, callback, "json" ); }, getScript: function( url, callback ) { return jQuery.get( url, undefined, callback, "script" ); } } ); jQuery.each( [ "get", "post" ], function( i, method ) { jQuery[ method ] = function( url, data, callback, type ) { // Shift arguments if data argument was omitted if ( jQuery.isFunction( data ) ) { type = type || callback; callback = data; data = undefined; } // The url can be an options object (which then must have .url) return jQuery.ajax( jQuery.extend( { url: url, type: method, dataType: type, data: data, success: callback }, jQuery.isPlainObject( url ) && url ) ); }; } ); jQuery._evalUrl = function( url ) { return jQuery.ajax( { url: url, // Make this explicit, since user can override this through ajaxSetup (#11264) type: "GET", dataType: "script", cache: true, async: false, global: false, "throws": true } ); }; jQuery.fn.extend( { wrapAll: function( html ) { var wrap; if ( this[ 0 ] ) { if ( jQuery.isFunction( html ) ) { html = html.call( this[ 0 ] ); } // The elements to wrap the target around wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); if ( this[ 0 ].parentNode ) { wrap.insertBefore( this[ 0 ] ); } wrap.map( function() { var elem = this; while ( elem.firstElementChild ) { elem = elem.firstElementChild; } return elem; } ).append( this ); } return this; }, wrapInner: function( html ) { if ( jQuery.isFunction( html ) ) { return this.each( function( i ) { jQuery( this ).wrapInner( html.call( this, i ) ); } ); } return this.each( function() { var self = jQuery( this ), contents = self.contents(); if ( contents.length ) { contents.wrapAll( html ); } else { self.append( html ); } } ); }, wrap: function( html ) { var isFunction = jQuery.isFunction( html ); return this.each( function( i ) { jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); } ); }, unwrap: function( selector ) { this.parent( selector ).not( "body" ).each( function() { jQuery( this ).replaceWith( this.childNodes ); } ); return this; } } ); jQuery.expr.pseudos.hidden = function( elem ) { return !jQuery.expr.pseudos.visible( elem ); }; jQuery.expr.pseudos.visible = function( elem ) { return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); }; jQuery.ajaxSettings.xhr = function() { try { return new window.XMLHttpRequest(); } catch ( e ) {} }; var xhrSuccessStatus = { // File protocol always yields status code 0, assume 200 0: 200, // Support: IE <=9 only // #1450: sometimes IE returns 1223 when it should be 204 1223: 204 }, xhrSupported = jQuery.ajaxSettings.xhr(); support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); support.ajax = xhrSupported = !!xhrSupported; jQuery.ajaxTransport( function( options ) { var callback, errorCallback; // Cross domain only allowed if supported through XMLHttpRequest if ( support.cors || xhrSupported && !options.crossDomain ) { return { send: function( headers, complete ) { var i, xhr = options.xhr(); xhr.open( options.type, options.url, options.async, options.username, options.password ); // Apply custom fields if provided if ( options.xhrFields ) { for ( i in options.xhrFields ) { xhr[ i ] = options.xhrFields[ i ]; } } // Override mime type if needed if ( options.mimeType && xhr.overrideMimeType ) { xhr.overrideMimeType( options.mimeType ); } // X-Requested-With header // For cross-domain requests, seeing as conditions for a preflight are // akin to a jigsaw puzzle, we simply never set it to be sure. // (it can always be set on a per-request basis or even using ajaxSetup) // For same-domain requests, won't change header if already provided. if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { headers[ "X-Requested-With" ] = "XMLHttpRequest"; } // Set headers for ( i in headers ) { xhr.setRequestHeader( i, headers[ i ] ); } // Callback callback = function( type ) { return function() { if ( callback ) { callback = errorCallback = xhr.onload = xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; if ( type === "abort" ) { xhr.abort(); } else if ( type === "error" ) { // Support: IE <=9 only // On a manual native abort, IE9 throws // errors on any property access that is not readyState if ( typeof xhr.status !== "number" ) { complete( 0, "error" ); } else { complete( // File: protocol always yields status 0; see #8605, #14207 xhr.status, xhr.statusText ); } } else { complete( xhrSuccessStatus[ xhr.status ] || xhr.status, xhr.statusText, // Support: IE <=9 only // IE9 has no XHR2 but throws on binary (trac-11426) // For XHR2 non-text, let the caller handle it (gh-2498) ( xhr.responseType || "text" ) !== "text" || typeof xhr.responseText !== "string" ? { binary: xhr.response } : { text: xhr.responseText }, xhr.getAllResponseHeaders() ); } } }; }; // Listen to events xhr.onload = callback(); errorCallback = xhr.onerror = callback( "error" ); // Support: IE 9 only // Use onreadystatechange to replace onabort // to handle uncaught aborts if ( xhr.onabort !== undefined ) { xhr.onabort = errorCallback; } else { xhr.onreadystatechange = function() { // Check readyState before timeout as it changes if ( xhr.readyState === 4 ) { // Allow onerror to be called first, // but that will not handle a native abort // Also, save errorCallback to a variable // as xhr.onerror cannot be accessed window.setTimeout( function() { if ( callback ) { errorCallback(); } } ); } }; } // Create the abort callback callback = callback( "abort" ); try { // Do send the request (this may raise an exception) xhr.send( options.hasContent && options.data || null ); } catch ( e ) { // #14683: Only rethrow if this hasn't been notified as an error yet if ( callback ) { throw e; } } }, abort: function() { if ( callback ) { callback(); } } }; } } ); // Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) jQuery.ajaxPrefilter( function( s ) { if ( s.crossDomain ) { s.contents.script = false; } } ); // Install script dataType jQuery.ajaxSetup( { accepts: { script: "text/javascript, application/javascript, " + "application/ecmascript, application/x-ecmascript" }, contents: { script: /\b(?:java|ecma)script\b/ }, converters: { "text script": function( text ) { jQuery.globalEval( text ); return text; } } } ); // Handle cache's special case and crossDomain jQuery.ajaxPrefilter( "script", function( s ) { if ( s.cache === undefined ) { s.cache = false; } if ( s.crossDomain ) { s.type = "GET"; } } ); // Bind script tag hack transport jQuery.ajaxTransport( "script", function( s ) { // This transport only deals with cross domain requests if ( s.crossDomain ) { var script, callback; return { send: function( _, complete ) { script = jQuery( "